diff --git a/CHANGELOG b/CHANGELOG
index 45b1e4bb5a..9f055c6405 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,6 +6,8 @@ v 8.1.0
v 8.0.1
v 8.1.0 (unreleased)
v 8.2.0 (unreleased)
+ - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
+ - Improved performance of finding users by one of their Email addresses
- 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
@@ -13,12 +15,43 @@ v 8.2.0 (unreleased)
- 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)
+ - Fix: Inability to reply to code comments in the MR view, if the MR comes from a fork
+ - Use git follow flag for commits page when retrieve history for file or directory
+ - Show merge request CI status on merge requests index page
+ - Extend yml syntax for only and except to support specifying repository path
+ - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
+ - Remove deprecated CI events from project settings page
+ - Use issue editor as cross reference comment author when issue is edited with a new mention.
+ - [API] Add ability to fetch the commit ID of the last commit that actually touched a file
+ - Add "New file" link to dropdown on project page
+ - Include commit logs in project search
+ - Add "added", "modified" and "removed" properties to commit object in webhook
+ - Rename "Back to" links to "Go to" because its not always a case it point to place user come from
+ - Allow groups to appear in the search results if the group owner allows it
+
+v 8.1.3
+ - Spread out runner contacted_at updates
+ - New design for user profile page
+ - Add Facebook authentication
+
+v 8.1.1
+ - Fix cloning Wiki repositories via HTTP (Stan Hu)
+ - Add migration to remove satellites directory
+ - Fix specific runners visibility
+ - Fix 500 when editing CI service
+ - Require CI jobs to be named
+ - Fix CSS for runner status
+ - Fix CI badge
+ - Allow developer to manage builds
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
+ - Adds ability to create directories using the web editor (Ben Ford)
+ - Cleanup stuck CI builds
+
+v 8.1.0 (unreleased)
- 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.
@@ -26,12 +59,11 @@ v 8.1.0
- 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
+ - Fix CI rendering regressions
- 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)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 69abadb151..9f79ff413a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -83,6 +83,7 @@ If you can, please submit a merge request with the fix or improvements including
1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submission
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
1. Also have a look at the [shell command guidelines](doc/development/shell_commands.md) if your code reads or opens files, or handles paths to files on disk.
+1. If your code creates new files on disk please read the [shared files guidelines](doc/development/shared_files.md).
The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast.
Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as regressions requiring patch releases.
diff --git a/GITLAB_GIT_HTTP_SERVER_VERSION b/GITLAB_GIT_HTTP_SERVER_VERSION
deleted file mode 100644
index 0d91a54c7d..0000000000
--- a/GITLAB_GIT_HTTP_SERVER_VERSION
+++ /dev/null
@@ -1 +0,0 @@
-0.3.0
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 57cf282ebb..338a5b5d8f 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-2.6.5
+2.6.6
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
new file mode 100644
index 0000000000..9e11b32fca
--- /dev/null
+++ b/GITLAB_WORKHORSE_VERSION
@@ -0,0 +1 @@
+0.3.1
diff --git a/Gemfile b/Gemfile
index b34d5e3c4d..acaf97e6f3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -19,6 +19,7 @@ gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.1.3'
gem 'omniauth', '~> 1.2.2'
gem 'omniauth-bitbucket', '~> 0.0.2'
+gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0'
@@ -65,7 +66,7 @@ gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Format dates and times
# based on human-friendly examples
-gem "stamp", '~> 0.5.0'
+gem "stamp", '~> 0.6.0'
# Enumeration fields
gem 'enumerize', '~> 0.7.0'
@@ -199,11 +200,11 @@ gem 'bootstrap-sass', '~> 3.0'
gem 'font-awesome-rails', '~> 4.2'
gem 'gitlab_emoji', '~> 0.1'
gem 'gon', '~> 5.0.0'
-gem 'jquery-atwho-rails', '~> 1.0.0'
+gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 3.1.3'
gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 4.2.1'
-gem 'nprogress-rails', '~> 0.1.2.3'
+gem 'nprogress-rails', '~> 0.1.6.7'
gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0'
gem 'select2-rails', '~> 3.5.9'
diff --git a/Gemfile.lock b/Gemfile.lock
index cdb99a51f4..7198be2ee1 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -357,7 +357,7 @@ GEM
ice_nine (0.11.1)
inflecto (0.0.2)
ipaddress (0.8.0)
- jquery-atwho-rails (1.0.1)
+ jquery-atwho-rails (1.3.2)
jquery-rails (3.1.3)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
@@ -409,7 +409,7 @@ GEM
newrelic_rpm (3.9.4.245)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
- nprogress-rails (0.1.2.3)
+ nprogress-rails (0.1.6.7)
oauth (0.4.7)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
@@ -426,6 +426,8 @@ GEM
multi_json (~> 1.7)
omniauth (~> 1.1)
omniauth-oauth (~> 1.0)
+ omniauth-facebook (3.0.0)
+ omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
@@ -692,7 +694,7 @@ GEM
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
- stamp (0.5.0)
+ stamp (0.6.0)
state_machine (1.2.0)
stringex (2.5.2)
systemu (2.6.5)
@@ -845,7 +847,7 @@ DEPENDENCIES
hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0)
httparty (~> 0.13.3)
- jquery-atwho-rails (~> 1.0.0)
+ jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 3.1.3)
jquery-scrollto-rails (~> 1.4.3)
jquery-turbolinks (~> 2.0.1)
@@ -860,11 +862,12 @@ DEPENDENCIES
net-ldap
newrelic-grape
newrelic_rpm (~> 3.9.4.245)
- nprogress-rails (~> 0.1.2.3)
+ nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0)
octokit (~> 3.7.0)
omniauth (~> 1.2.2)
omniauth-bitbucket (~> 0.0.2)
+ omniauth-facebook (~> 3.0.0)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.0)
@@ -915,7 +918,7 @@ DEPENDENCIES
spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 2.12.3)
- stamp (~> 0.5.0)
+ stamp (~> 0.6.0)
state_machine (~> 1.2.0)
task_list (~> 1.0.2)
teaspoon (~> 1.0.0)
diff --git a/PROCESS.md b/PROCESS.md
index 9f4b708d2b..d42168a723 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -115,3 +115,10 @@ We can only accept a merge request if all the tests are green. I've just
restarted the build. When the tests are still not passing after this restart and
you're sure that is does not have anything to do with your code changes, please
rebase with master to see if that solves the issue.
+
+### Closing down the issue tracker on GitHub
+
+We are currently in the process of closing down the issue tracker on GitHub, to
+prevent duplication with the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues].
+Since this is an older issue I'll be closing this for now. If you think this is
+still an issue I encourage you to open it on the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues].
diff --git a/app/assets/fonts/SourceSansPro-Black.ttf b/app/assets/fonts/SourceSansPro-Black.ttf
old mode 100755
new mode 100644
index cb89a2d171..9c9b5cb7f0
Binary files a/app/assets/fonts/SourceSansPro-Black.ttf and b/app/assets/fonts/SourceSansPro-Black.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf b/app/assets/fonts/SourceSansPro-BlackIt.ttf
new file mode 100644
index 0000000000..294ce5abe8
Binary files /dev/null and b/app/assets/fonts/SourceSansPro-BlackIt.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf b/app/assets/fonts/SourceSansPro-Bold.ttf
old mode 100755
new mode 100644
diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf b/app/assets/fonts/SourceSansPro-BoldIt.ttf
new file mode 100644
index 0000000000..3decd13007
Binary files /dev/null and b/app/assets/fonts/SourceSansPro-BoldIt.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf b/app/assets/fonts/SourceSansPro-ExtraLight.ttf
old mode 100755
new mode 100644
index bb4176c6ff..253eafa378
Binary files a/app/assets/fonts/SourceSansPro-ExtraLight.ttf and b/app/assets/fonts/SourceSansPro-ExtraLight.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf
new file mode 100644
index 0000000000..00d7e9a7aa
Binary files /dev/null and b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-It.ttf b/app/assets/fonts/SourceSansPro-It.ttf
new file mode 100644
index 0000000000..f7af537759
Binary files /dev/null and b/app/assets/fonts/SourceSansPro-It.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-Light.ttf b/app/assets/fonts/SourceSansPro-Light.ttf
old mode 100755
new mode 100644
diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf b/app/assets/fonts/SourceSansPro-LightIt.ttf
new file mode 100644
index 0000000000..f18827985e
Binary files /dev/null and b/app/assets/fonts/SourceSansPro-LightIt.ttf differ
diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf b/app/assets/fonts/SourceSansPro-Regular.ttf
old mode 100755
new mode 100644
diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf b/app/assets/fonts/SourceSansPro-Semibold.ttf
old mode 100755
new mode 100644
diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf
new file mode 100644
index 0000000000..13d66a1fc4
Binary files /dev/null and b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf differ
diff --git a/app/assets/images/auth_buttons/facebook_64.png b/app/assets/images/auth_buttons/facebook_64.png
new file mode 100644
index 0000000000..1f1a80d736
Binary files /dev/null and b/app/assets/images/auth_buttons/facebook_64.png differ
diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee
index 050888f9c1..f6bf836f19 100644
--- a/app/assets/javascripts/blob/edit_blob.js.coffee
+++ b/app/assets/javascripts/blob/edit_blob.js.coffee
@@ -11,10 +11,10 @@ class @EditBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
- $(".js-commit-button").click ->
- $("#file-content").val editor.getValue()
- $(".file-editor form").submit()
- return false
+ # Before a form submission, move the content from the Ace editor into the
+ # submitted textarea
+ $('form').submit ->
+ $("#file-content").val(editor.getValue())
editModePanes = $(".js-edit-mode-pane")
editModeLinks = $(".js-edit-mode a")
diff --git a/app/assets/javascripts/blob/new_blob.js.coffee b/app/assets/javascripts/blob/new_blob.js.coffee
index 1f36a53f19..68c5e5195e 100644
--- a/app/assets/javascripts/blob/new_blob.js.coffee
+++ b/app/assets/javascripts/blob/new_blob.js.coffee
@@ -11,10 +11,10 @@ class @NewBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
- $(".js-commit-button").click ->
- $("#file-content").val editor.getValue()
- $(".file-editor form").submit()
- return false
+ # Before a form submission, move the content from the Ace editor into the
+ # submitted textarea
+ $('form').submit ->
+ $("#file-content").val(editor.getValue())
editor: ->
return @editor
diff --git a/app/assets/javascripts/calendar.js.coffee b/app/assets/javascripts/calendar.js.coffee
index 4c4bc3d66e..9762123692 100644
--- a/app/assets/javascripts/calendar.js.coffee
+++ b/app/assets/javascripts/calendar.js.coffee
@@ -25,7 +25,7 @@ class @Calendar
30
]
legendCellPadding: 3
- cellSize: $('.user-calendar').width() / 80
+ cellSize: $('.user-calendar').width() / 73
onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
$.ajax
diff --git a/app/assets/javascripts/ci/build.coffee b/app/assets/javascripts/ci/build.coffee
index 93385b32a1..44d5ddb7d9 100644
--- a/app/assets/javascripts/ci/build.coffee
+++ b/app/assets/javascripts/ci/build.coffee
@@ -31,7 +31,7 @@ class CiBuild
$('#build-trace code').html build.trace_html
$('#build-trace code').append ''
@checkAutoscroll()
- else
+ else if build.status != build_status
Turbolinks.visit build_url
, 4000
diff --git a/app/assets/javascripts/copy_to_clipboard.js.coffee b/app/assets/javascripts/copy_to_clipboard.js.coffee
new file mode 100644
index 0000000000..ec4b80cca6
--- /dev/null
+++ b/app/assets/javascripts/copy_to_clipboard.js.coffee
@@ -0,0 +1,21 @@
+#= require clipboard
+
+$ ->
+ clipboard = new Clipboard '.js-clipboard-trigger',
+ text: (trigger) ->
+ $target = $(trigger.nextElementSibling || trigger.previousElementSibling)
+ $target.data('clipboard-text') || $target.text().trim()
+
+ clipboard.on 'success', (e) ->
+ $(e.trigger).
+ tooltip(trigger: 'manual', placement: 'auto bottom', title: 'Copied!').
+ tooltip('show')
+
+ # Clear the selection and blur the trigger so it loses its border
+ e.clearSelection()
+ $(e.trigger).blur()
+
+ # Manually hide the tooltip after 1 second
+ setTimeout(->
+ $(e.trigger).tooltip('hide')
+ , 1000)
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 5949a0fd5a..8917c53b1f 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -100,7 +100,7 @@
}
.cover-desc {
- padding: 0 $gl-padding;
+ padding: 0 $gl-padding 3px;
color: $gl-text-color;
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 0402441958..fe56266284 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -180,3 +180,7 @@
}
}
}
+
+.btn-clipboard {
+ border: none;
+}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 82e3244504..6dbbf52212 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -396,6 +396,36 @@ table {
}
}
+.center-middle-menu {
+ @include nav-menu;
+ padding: 0;
+ text-align: center;
+ margin: -$gl-padding;
+ margin-top: 0;
+ margin-bottom: 0;
+ height: 58px;
+ border-bottom: 1px solid $border-color;
+
+ li {
+ &:after {
+ content: "|";
+ color: $border-gray-light;
+ }
+
+ &:last-child {
+ &:after {
+ content: none;
+ }
+ }
+
+ > a {
+ display: inline-block;
+ text-transform: uppercase;
+ font-size: 13px;
+ }
+ }
+}
+
.dropzone .dz-preview .dz-progress {
border-color: $border-color !important;
}
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index fe078d016d..b9c179f288 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -137,6 +137,7 @@
&:hover, &:active, &:focus {
text-decoration: none;
+ outline: none;
}
}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 4e121b95d1..e485487bcf 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -33,6 +33,8 @@
}
li.commit {
+ list-style: none;
+
.commit-row-title {
font-size: $list-font-size;
line-height: 20px;
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 1d565477dd..e2c521af91 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -50,7 +50,7 @@
.editor-file-name {
.new-file-name {
display: inline-block;
- width: 200px;
+ width: 450px;
}
.form-control {
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index c60aa5c7fe..abc27a19e3 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -88,3 +88,16 @@
padding: 13px 0;
}
}
+
+.cross-project-reference {
+ text-align: center;
+ width: 100%;
+
+ .slead {
+ padding: 5px;
+ }
+
+ span, button {
+ background-color: $background-color;
+ }
+}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index a1a5208c59..f0b3667acc 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -205,6 +205,15 @@
#modal_merge_info .modal-dialog {
width: 600px;
+
+ .btn-clipboard {
+ @extend .pull-right;
+
+ margin-right: 18px;
+ margin-top: 5px;
+ position: absolute;
+ right: 0;
+ }
}
.mr-source-target {
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index b7391e5303..1d6ca0dfc1 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -53,3 +53,25 @@
float: right;
font-size: 12px;
}
+
+.profile-link-holder {
+ display: inline;
+
+ &:after {
+ content: "\00B7";
+ padding: 0px 6px;
+ font-weight: bold;
+ }
+
+ &:last-child {
+ &:after {
+ content: "";
+ padding: 0;
+ }
+ }
+
+ a {
+ color: $blue-dark;
+ text-decoration: none;
+ }
+}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index c4bd3eeca0..fb855f9e07 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -59,13 +59,8 @@ class ApplicationController < ActionController::Base
end
def authenticate_user!(*args)
- # If user is not signed-in and tries to access root_path - redirect him to landing page
- # Don't redirect to the default URL to prevent endless redirections
- if current_application_settings.home_page_url.present? &&
- current_application_settings.home_page_url.chomp('/') != Gitlab.config.gitlab['url'].chomp('/')
- if current_user.nil? && root_path == request.path
- redirect_to current_application_settings.home_page_url and return
- end
+ if redirect_to_home_page_url?
+ redirect_to current_application_settings.home_page_url and return
end
super(*args)
@@ -352,4 +347,17 @@ class ApplicationController < ActionController::Base
def git_import_enabled?
current_application_settings.import_sources.include?('git')
end
+
+ def redirect_to_home_page_url?
+ # If user is not signed-in and tries to access root_path - redirect him to landing page
+ # Don't redirect to the default URL to prevent endless redirections
+ return false unless current_application_settings.home_page_url.present?
+
+ home_page_url = current_application_settings.home_page_url.chomp('/')
+ root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
+
+ return false if root_urls.include?(home_page_url)
+
+ current_user.nil? && root_path == request.path
+ end
end
diff --git a/app/controllers/ci/admin/runners_controller.rb b/app/controllers/ci/admin/runners_controller.rb
index 110954a612..0cafad2741 100644
--- a/app/controllers/ci/admin/runners_controller.rb
+++ b/app/controllers/ci/admin/runners_controller.rb
@@ -17,6 +17,7 @@ module Ci
@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.joins(:gl_project)
@projects = @projects.page(params[:page]).per(30)
end
diff --git a/app/controllers/ci/application_controller.rb b/app/controllers/ci/application_controller.rb
index 9be470660e..848f2b4e31 100644
--- a/app/controllers/ci/application_controller.rb
+++ b/app/controllers/ci/application_controller.rb
@@ -8,14 +8,6 @@ module Ci
private
- def authenticate_public_page!
- unless project.public
- authenticate_user!
-
- return access_denied! unless can?(current_user, :read_project, gl_project)
- end
- end
-
def authenticate_token!
unless project.valid_token?(params[:token])
return head(403)
diff --git a/app/controllers/ci/events_controller.rb b/app/controllers/ci/events_controller.rb
deleted file mode 100644
index 89b784a1e8..0000000000
--- a/app/controllers/ci/events_controller.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module Ci
- class EventsController < Ci::ApplicationController
- EVENTS_PER_PAGE = 50
-
- before_action :authenticate_user!
- before_action :project
- before_action :authorize_manage_project!
-
- layout 'ci/project'
-
- def index
- @events = project.events.order("created_at DESC").page(params[:page]).per(EVENTS_PER_PAGE)
- end
-
- private
-
- def project
- @project ||= Ci::Project.find(params[:project_id])
- end
- end
-end
diff --git a/app/controllers/ci/runner_projects_controller.rb b/app/controllers/ci/runner_projects_controller.rb
index 97f01d40af..9d55531336 100644
--- a/app/controllers/ci/runner_projects_controller.rb
+++ b/app/controllers/ci/runner_projects_controller.rb
@@ -4,8 +4,6 @@ module Ci
before_action :project
before_action :authorize_manage_project!
- layout 'ci/project'
-
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index d9071d4f1c..a9df360178 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -4,12 +4,12 @@ class GroupsController < Groups::ApplicationController
before_action :group, except: [:new, :create]
# Authorize
- before_action :authorize_read_group!, except: [:show, :new, :create]
+ before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create]
# Load group projects
- before_action :load_projects, except: [:new, :create, :projects, :edit, :update]
+ before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: :show
layout :determine_layout
@@ -135,7 +135,7 @@ class GroupsController < Groups::ApplicationController
end
def group_params
- params.require(:group).permit(:name, :description, :path, :avatar, :membership_lock, :share_with_group_lock)
+ params.require(:group).permit(:name, :description, :path, :avatar, :membership_lock, :share_with_group_lock, :public)
end
def load_events
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 8cc2f21d88..93738aa1ee 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present?
params[:file_name] = params[:file].original_filename
end
- File.join(@path, File.basename(params[:file_name]))
+ File.join(@path, params[:file_name])
else
@path
end
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 816012762c..7d72e0b951 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -2,23 +2,24 @@ 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]
+ before_action :authorize_manage_builds!, except: [:index, :show, :status]
layout "project"
def index
@scope = params[:scope]
@all_builds = project.ci_builds
+ @builds = @all_builds.order('created_at DESC')
@builds =
case @scope
when 'all'
- @all_builds
+ @builds
when 'finished'
- @all_builds.finished
+ @builds.finished
else
- @all_builds.running_or_pending
+ @builds.running_or_pending.reverse_order
end
- @builds = @builds.order('created_at DESC').page(params[:page]).per(30)
+ @builds = @builds.page(params[:page]).per(30)
end
def cancel_all
@@ -73,4 +74,10 @@ class Projects::BuildsController < Projects::ApplicationController
def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
end
+
+ def authorize_manage_builds!
+ unless can?(current_user, :manage_builds, project)
+ return page_404
+ end
+ end
end
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 7886f3c6de..878c3a66e7 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -4,7 +4,8 @@
class Projects::CommitController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
- before_action :authorize_download_code!
+ before_action :authorize_download_code!, except: [:cancel_builds]
+ before_action :authorize_manage_builds!, only: [:cancel_builds]
before_action :commit
def show
@@ -55,4 +56,12 @@ class Projects::CommitController < Projects::ApplicationController
def commit
@commit ||= @project.commit(params[:id])
end
+
+ private
+
+ def authorize_manage_builds!
+ unless can?(current_user, :manage_builds, project)
+ return page_404
+ end
+ end
end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index d1c15174ae..58fb946dbc 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -12,7 +12,7 @@ class Projects::CommitsController < Projects::ApplicationController
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @repo.commits(@ref, @path, @limit, @offset)
- @note_counts = Note.where(commit_id: @commits.map(&:id)).
+ @note_counts = project.notes.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
respond_to do |format|
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index deb07a2141..bfbcf2567f 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -6,11 +6,10 @@ class Projects::RunnersController < Projects::ApplicationController
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)
+ @runners = @ci_project.runners.ordered
+ @specific_runners = current_user.ci_authorized_runners.
+ where.not(id: @ci_project.runners).
+ ordered.page(params[:page]).per(20)
@shared_runners = Ci::Runner.shared.active
@shared_runners_count = @shared_runners.count(:all)
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index dd5a754647..4c240364e4 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -1,7 +1,7 @@
class ProjectsController < ApplicationController
include ExtractsPath
- prepend_before_filter :render_go_import, only: [:show]
+ prepend_before_action :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]
@@ -124,11 +124,7 @@ class ProjectsController < ApplicationController
::Projects::DestroyService.new(@project, current_user, {}).execute
flash[:alert] = "Project '#{@project.name}' was deleted."
- if request.referer.include?('/admin')
- redirect_to admin_namespaces_projects_path
- else
- redirect_to dashboard_projects_path
- end
+ redirect_back_or_default(default: dashboard_projects_path, options: {})
rescue Projects::DestroyService::DestroyError => ex
redirect_to edit_project_path(@project), alert: ex.message
end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index eb0408a95e..9bb42ec86b 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -23,8 +23,8 @@ class SearchController < ApplicationController
@search_results =
if @project
- unless %w(blobs notes issues merge_requests milestones wiki_blobs).
- include?(@scope)
+ unless %w(blobs notes issues merge_requests milestones wiki_blobs
+ commits).include?(@scope)
@scope = 'blobs'
end
diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb
index d3597ef090..b5f3176461 100644
--- a/app/finders/groups_finder.rb
+++ b/app/finders/groups_finder.rb
@@ -6,33 +6,34 @@ class GroupsFinder
private
def all_groups(current_user)
- if current_user
- if current_user.authorized_groups.any?
- # User has access to groups
- #
- # Return only:
- # groups with public projects
- # groups with internal projects
- # groups with joined projects
- #
- group_ids = Project.public_and_internal_only.pluck(:namespace_id) +
- current_user.authorized_groups.pluck(:id)
- Group.where(id: group_ids)
- else
- # User has no group membership
- #
- # Return only:
- # groups with public projects
- # groups with internal projects
- #
- Group.where(id: Project.public_and_internal_only.pluck(:namespace_id))
- end
- else
- # Not authenticated
- #
- # Return only:
- # groups with public projects
- Group.where(id: Project.public_only.pluck(:namespace_id))
- end
+ group_ids = if current_user
+ if current_user.authorized_groups.any?
+ # User has access to groups
+ #
+ # Return only:
+ # groups with public projects
+ # groups with internal projects
+ # groups with joined projects
+ #
+ Project.public_and_internal_only.pluck(:namespace_id) +
+ current_user.authorized_groups.pluck(:id)
+ else
+ # User has no group membership
+ #
+ # Return only:
+ # groups with public projects
+ # groups with internal projects
+ #
+ Project.public_and_internal_only.pluck(:namespace_id)
+ end
+ else
+ # Not authenticated
+ #
+ # Return only:
+ # groups with public projects
+ Project.public_only.pluck(:namespace_id)
+ end
+
+ Group.where("public IS TRUE OR id IN(?)", group_ids)
end
end
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index fe0c17d72a..6eae3d453f 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -1,5 +1,5 @@
module AuthHelper
- PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
+ PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook).freeze
FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos', 'crowd'].freeze
def ldap_enabled?
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index dbd1e26fa7..ed88df5dd8 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -42,4 +42,13 @@ module CiStatusHelper
icon(icon_name)
end
+
+ def render_ci_status(ci_commit)
+ link_to ci_status_path(ci_commit),
+ class: "c#{ci_status_color(ci_commit)}",
+ title: "Build status: #{ci_commit.status}",
+ data: { toggle: 'tooltip', placement: 'left' } do
+ ci_status_icon(ci_commit)
+ end
+ end
end
diff --git a/app/helpers/clipboard_helper.rb b/app/helpers/clipboard_helper.rb
new file mode 100644
index 0000000000..3c1d7569fa
--- /dev/null
+++ b/app/helpers/clipboard_helper.rb
@@ -0,0 +1,8 @@
+module ClipboardHelper
+ def clipboard_button
+ content_tag :button,
+ icon('clipboard'),
+ class: 'btn btn-xs btn-clipboard js-clipboard-trigger',
+ type: :button
+ end
+end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index c31a556ff7..a6ee688024 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -70,7 +70,7 @@ module SearchHelper
# Autocomplete results for the current user's groups
def groups_autocomplete(term, limit = 5)
- current_user.authorized_groups.search(term).limit(limit).map do |group|
+ GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group|
{
label: "group: #{search_result_sanitize(group.name)}",
url: group_path(group)
diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb
index 13437b2483..e58420d82d 100644
--- a/app/models/ci/commit.rb
+++ b/app/models/ci/commit.rb
@@ -187,7 +187,7 @@ module Ci
end
def config_processor
- @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file)
+ @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, gl_project.path_with_namespace)
rescue Ci::GitlabCiYamlProcessor::ValidationError => e
save_yaml_error(e.message)
nil
diff --git a/app/models/ci/project.rb b/app/models/ci/project.rb
index eb65c77357..4e806ca1a6 100644
--- a/app/models/ci/project.rb
+++ b/app/models/ci/project.rb
@@ -99,6 +99,7 @@ module Ci
def ordered_by_last_commit_date
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").
+ joins(:gl_project).
order("CASE WHEN last_commit.committed_at IS NULL THEN 1 ELSE 0 END, last_commit.committed_at DESC")
end
end
diff --git a/app/models/ci/project_status.rb b/app/models/ci/project_status.rb
index b66f1212f2..2d35aeac22 100644
--- a/app/models/ci/project_status.rb
+++ b/app/models/ci/project_status.rb
@@ -27,9 +27,5 @@ module Ci
def human_status
status
end
-
- def last_commit_for_ref(ref)
- commits.where(ref: ref).last
- end
end
end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 1b3669f1b7..b719ad3c87 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -36,6 +36,7 @@ module Ci
scope :active, ->() { where(active: true) }
scope :paused, ->() { where(active: false) }
scope :online, ->() { where('contacted_at > ?', LAST_CONTACT_TIME) }
+ scope :ordered, ->() { order(id: :desc) }
acts_as_taggable
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 8188ba3a28..0b73ab6d2e 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -20,7 +20,6 @@ class CommitStatus < ActiveRecord::Base
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
diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb
index 0ad2654867..913c747a1c 100644
--- a/app/models/concerns/sortable.rb
+++ b/app/models/concerns/sortable.rb
@@ -8,12 +8,12 @@ module Sortable
included do
# By default all models should be ordered
# by created_at field starting from newest
- default_scope { order(created_at: :desc, id: :desc) }
+ default_scope { order(id: :desc) }
- scope :order_created_desc, -> { reorder(created_at: :desc, id: :desc) }
- scope :order_created_asc, -> { reorder(created_at: :asc, id: :asc) }
- scope :order_updated_desc, -> { reorder(updated_at: :desc, id: :desc) }
- scope :order_updated_asc, -> { reorder(updated_at: :asc, id: :asc) }
+ scope :order_created_desc, -> { reorder(created_at: :desc) }
+ scope :order_created_asc, -> { reorder(created_at: :asc) }
+ scope :order_updated_desc, -> { reorder(updated_at: :desc) }
+ scope :order_updated_asc, -> { reorder(updated_at: :asc) }
scope :order_name_asc, -> { reorder(name: :asc) }
scope :order_name_desc, -> { reorder(name: :desc) }
end
diff --git a/app/models/group.rb b/app/models/group.rb
index e6eedc306d..46cf08e4a6 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -128,7 +128,7 @@ class Group < Namespace
end
def public_profile?
- projects.public_only.any?
+ self.public || projects.public_only.any?
end
# NOTE: Backwards compatibility with old ldap situation
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index b1179c1140..bfdc9681dc 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -163,11 +163,11 @@ class MergeRequest < ActiveRecord::Base
def last_commit
merge_request_diff ? merge_request_diff.last_commit : compare_commits.last
- end
+ end
def first_commit
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
- end
+ end
def last_commit_short_sha
last_commit.short_id
@@ -261,7 +261,7 @@ class MergeRequest < ActiveRecord::Base
Note.where(
"(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" +
- "(project_id = :source_project_id AND noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
+ "((project_id = :source_project_id OR project_id = :target_project_id) AND noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
mr_id: id,
commit_ids: commit_ids,
target_project_id: target_project_id,
@@ -542,4 +542,10 @@ class MergeRequest < ActiveRecord::Base
def rebase_in_progress?
File.exist?(rebase_dir_path)
end
+
+ def ci_commit
+ if last_commit
+ source_project.ci_commit(last_commit.id)
+ end
+ end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 15e9a1edf3..93fe284208 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -67,13 +67,16 @@ class Repository
end
def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false)
- commits = Gitlab::Git::Commit.where(
+ options = {
repo: raw_repository,
ref: ref,
path: path,
limit: limit,
offset: offset,
- )
+ follow: path.present?
+ }
+
+ commits = Gitlab::Git::Commit.where(options)
commits = Commit.decorate(commits, @project) if commits.present?
commits
end
@@ -84,6 +87,15 @@ class Repository
commits
end
+ def find_commits_by_message(query)
+ # Limited to 1000 commits for now, could be parameterized?
+ args = %W(#{Gitlab.config.git.bin_path} log --pretty=%H --max-count 1000 --grep=#{query})
+
+ git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp)
+ commits = git_log_results.map { |c| commit(c) }
+ commits
+ end
+
def find_branch(name)
branches.find { |branch| branch.name == name }
end
@@ -284,7 +296,7 @@ class Repository
end
def last_commit_for_path(sha, path)
- args = %W(git rev-list --max-count=1 #{sha} -- #{path})
+ args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path})
sha = Gitlab::Popen.popen(args, path_to_repo).first.strip
commit(sha)
end
@@ -335,7 +347,7 @@ class Repository
end
def branch_names_contains(sha)
- args = %W(git branch --contains #{sha})
+ args = %W(#{Gitlab.config.git.bin_path} branch --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split)
@@ -352,7 +364,7 @@ class Repository
end
def tag_names_contains(sha)
- args = %W(git tag --contains #{sha})
+ args = %W(#{Gitlab.config.git.bin_path} tag --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split)
@@ -505,7 +517,7 @@ class Repository
def search_files(query, ref)
offset = 2
- args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref})
+ args = %W(#{Gitlab.config.git.bin_path} grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref})
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
@@ -537,7 +549,7 @@ class Repository
end
def fetch_ref(source_path, source_ref, target_ref)
- args = %W(git fetch #{source_path} #{source_ref}:#{target_ref})
+ args = %W(#{Gitlab.config.git.bin_path} fetch -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo)
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 96e76a366f..d7421227a4 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -238,21 +238,16 @@ class User < ActiveRecord::Base
# Find a User by their primary email or any associated secondary email
def find_by_any_email(email)
- user_table = arel_table
- email_table = Email.arel_table
+ sql = 'SELECT *
+ FROM users
+ WHERE id IN (
+ SELECT id FROM users WHERE email = :email
+ UNION
+ SELECT emails.user_id FROM emails WHERE email = :email
+ )
+ LIMIT 1;'
- # Use ARel to build a query:
- query = user_table.
- # SELECT "users".* FROM "users"
- project(user_table[Arel.star]).
- # LEFT OUTER JOIN "emails"
- join(email_table, Arel::Nodes::OuterJoin).
- # ON "users"."id" = "emails"."user_id"
- on(user_table[:id].eq(email_table[:user_id])).
- # WHERE ("user"."email" = '' OR "emails"."email" = '')
- where(user_table[:email].eq(email).or(email_table[:email].eq(email)))
-
- find_by_sql(query.to_sql).first
+ User.find_by_sql([sql, { email: email }]).first
end
def existing_member?(email)
@@ -429,16 +424,18 @@ class User < ActiveRecord::Base
end
end
+ def authorized_projects_id
+ @authorized_projects_id ||= begin
+ project_ids = personal_projects.pluck(:id)
+ project_ids.push(*groups_projects.pluck(:id))
+ project_ids.push(*projects.pluck(:id).uniq)
+ project_ids.push(*groups.joins(:shared_projects).pluck(:project_id))
+ end
+ end
# Projects user has access to
def authorized_projects
- @authorized_projects ||= begin
- project_ids = personal_projects.pluck(:id)
- project_ids.push(*groups_projects.pluck(:id))
- project_ids.push(*projects.pluck(:id).uniq)
- project_ids.push(*groups.joins(:shared_projects).pluck(:project_id))
- Project.where(id: project_ids)
- end
+ @authorized_projects ||= Project.where(id: authorized_projects_id)
end
def owned_projects
@@ -801,11 +798,14 @@ class User < ActiveRecord::Base
end
def ci_authorized_projects
- @ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects)
+ @ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects_id)
end
def ci_authorized_runners
- Ci::Runner.specific.includes(:runner_projects).
- where(ci_runner_projects: { project_id: ci_authorized_projects } )
+ @ci_authorized_runners ||= begin
+ runner_ids = Ci::RunnerProject.joins(:project).
+ where(ci_projects: { gitlab_id: authorized_projects_id }).select(:runner_id)
+ Ci::Runner.specific.where(id: runner_ids)
+ end
end
end
diff --git a/app/services/ci/image_for_build_service.rb b/app/services/ci/image_for_build_service.rb
index b95835ba09..b8d2419303 100644
--- a/app/services/ci/image_for_build_service.rb
+++ b/app/services/ci/image_for_build_service.rb
@@ -1,17 +1,15 @@
module Ci
class ImageForBuildService
def execute(project, params)
- image_name =
- if params[:sha]
- commit = project.commits.find_by(sha: params[:sha])
- image_for_commit(commit)
- elsif params[:ref]
- commit = project.last_commit_for_ref(params[:ref])
- image_for_commit(commit)
- else
- 'build-unknown.svg'
+ sha = params[:sha]
+ sha ||=
+ if params[:ref]
+ project.gl_project.commit(params[:ref]).try(:sha)
end
+ commit = project.commits.ordered.find_by(sha: sha)
+ image_name = image_for_commit(commit)
+
image_path = Rails.root.join('public/ci', image_name)
OpenStruct.new(
diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb
index 71272fb570..6107254a34 100644
--- a/app/services/files/create_dir_service.rb
+++ b/app/services/files/create_dir_service.rb
@@ -5,5 +5,16 @@ module Files
def commit
repository.commit_dir(current_user, @file_path, @commit_message, @target_branch)
end
+
+ def validate
+ super
+
+ unless @file_path =~ Gitlab::Regex.file_path_regex
+ raise_error(
+ 'Your changes could not be committed, because the file path ' +
+ Gitlab::Regex.file_path_regex_message
+ )
+ end
+ end
end
end
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index c8e3a910bb..2348920cc5 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -9,12 +9,17 @@ module Files
def validate
super
- file_name = File.basename(@file_path)
-
- unless file_name =~ Gitlab::Regex.file_name_regex
+ if @file_path =~ Gitlab::Regex.directory_traversal_regex
raise_error(
'Your changes could not be committed, because the file name ' +
- Gitlab::Regex.file_name_regex_message
+ Gitlab::Regex.directory_traversal_regex_message
+ )
+ end
+
+ unless @file_path =~ Gitlab::Regex.file_path_regex
+ raise_error(
+ 'Your changes could not be committed, because the file name ' +
+ Gitlab::Regex.file_path_regex_message
)
end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 2b5426ad45..551325e4ca 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.create_new_cross_references!(current_user)
execute_hooks(issue, 'update')
end
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index ebbe0af803..61f7d2bbe8 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.create_new_cross_references!(current_user)
execute_hooks(merge_request, 'update')
end
diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb
index 6c2f08e596..72e2f78008 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.create_new_cross_references!(current_user)
note.reset_events_cache
note
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 6918415311..cef76a51cb 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -94,8 +94,6 @@ module Projects
@project.team << [current_user, :master, current_user]
end
- @project.update_column(:last_activity_at, @project.created_at)
-
if @project.import?
@project.import_start
end
diff --git a/app/views/ci/admin/runner_projects/index.html.haml b/app/views/ci/admin/runner_projects/index.html.haml
index f049b4f4c4..6b4e3b2cb3 100644
--- a/app/views/ci/admin/runner_projects/index.html.haml
+++ b/app/views/ci/admin/runner_projects/index.html.haml
@@ -1,5 +1,5 @@
%p.lead
- To register new runner visit #{link_to 'this page ', ci_runners_path}
+ To register a new runner visit #{link_to 'this page ', ci_runners_path}
.row
.col-md-8
diff --git a/app/views/ci/admin/runners/index.html.haml b/app/views/ci/admin/runners/index.html.haml
index bb213fbffc..bacaccfbff 100644
--- a/app/views/ci/admin/runners/index.html.haml
+++ b/app/views/ci/admin/runners/index.html.haml
@@ -1,5 +1,5 @@
%p.lead
- %span To register new runner you should enter the following registration token. With this token the runner will request a unique runner token and use that for future communication.
+ %span To register a new runner you should enter the following registration token. With this token the runner will request a unique runner token and use that for future communication.
%code #{GitlabCi::REGISTRATION_TOKEN}
.bs-callout
@@ -21,7 +21,7 @@
\- run builds from assigned projects
%li
%span.label.label-danger paused
- \- runner will not receive any new build
+ \- runner will not receive any new builds
.append-bottom-20.clearfix
.pull-left
diff --git a/app/views/ci/admin/runners/show.html.haml b/app/views/ci/admin/runners/show.html.haml
index 92787b2e6a..1498db46a8 100644
--- a/app/views/ci/admin/runners/show.html.haml
+++ b/app/views/ci/admin/runners/show.html.haml
@@ -13,13 +13,13 @@
- if @runner.shared?
.bs-callout.bs-callout-success
- %h4 This runner will process build from ALL UNASSIGNED projects
+ %h4 This runner will process builds from ALL UNASSIGNED projects
%p
If you want runners to build only specific projects, enable them in the table below.
Keep in mind that this is a one way transition.
- else
.bs-callout.bs-callout-info
- %h4 This runner will process build only from ASSIGNED projects
+ %h4 This runner will process builds only from ASSIGNED projects
%p You can't make this a shared runner.
%hr
= form_for @runner, url: ci_admin_runner_path(@runner), html: { class: 'form-horizontal' } do |f|
@@ -53,13 +53,14 @@
%th
- @runner.runner_projects.each do |runner_project|
- project = runner_project.project
- %tr.alert-info
- %td
- %strong
- = project.name
- %td
- .pull-right
- = link_to 'Disable', [:ci, :admin, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
+ - if project.gl_project
+ %tr.alert-info
+ %td
+ %strong
+ = project.name
+ %td
+ .pull-right
+ = link_to 'Disable', [:ci, :admin, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
%table.table
%thead
@@ -103,21 +104,26 @@
%th Finished at
- @builds.each do |build|
+ - gl_project = build.gl_project
%tr.build
%td.id
- - gl_project = build.project.gl_project
- = link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
+ - if gl_project
+ = link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
+ = build.id
+ - else
= build.id
%td.status
= ci_status_with_icon(build.status)
%td.status
- = build.project.name
+ - if gl_project
+ = gl_project.name_with_namespace
%td.build-link
- = link_to ci_status_path(build.commit) do
- %strong #{build.commit.short_sha}
+ - if gl_project
+ = 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/events/index.html.haml b/app/views/ci/events/index.html.haml
deleted file mode 100644
index 9824e85b1a..0000000000
--- a/app/views/ci/events/index.html.haml
+++ /dev/null
@@ -1,20 +0,0 @@
-%h3.page-title Events
-
-.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
diff --git a/app/views/ci/lints/_create.html.haml b/app/views/ci/lints/_create.html.haml
index f45cd05aec..77f78caa8d 100644
--- a/app/views/ci/lints/_create.html.haml
+++ b/app/views/ci/lints/_create.html.haml
@@ -17,7 +17,7 @@
%td #{stage.capitalize} Job - #{build[:name]}
%td
%pre
- = simple_format build[:script]
+ = simple_format build[:commands]
%br
%b Tag list:
@@ -28,6 +28,11 @@
%br
%b Refs except:
= build[:except] && build[:except].join(", ")
+ %br
+ %b When:
+ = build[:when]
+ - if build[:allow_failure]
+ %b Allowed to fail
-else
%p
diff --git a/app/views/ci/user_sessions/new.html.haml b/app/views/ci/user_sessions/new.html.haml
index 308b217ea7..b8d9a1d708 100644
--- a/app/views/ci/user_sessions/new.html.haml
+++ b/app/views/ci/user_sessions/new.html.haml
@@ -1,8 +1,7 @@
.login-block
%h2 Login using GitLab account
%p.light
- Make sure you have account on GitLab server
+ Make sure you have an account on the GitLab server
= link_to GitlabCi.config.gitlab_server.url, GitlabCi.config.gitlab_server.url, no_turbolink
%hr
= link_to "Login with GitLab", auth_ci_user_sessions_path(state: params[:state]), no_turbolink.merge( class: 'btn btn-login btn-success' )
-
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index 9c95515a31..6f55e9b018 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -43,6 +43,15 @@
= f.check_box :share_with_group_lock
%span.descr Prevent sharing a project with another group within this group
+ .form-group
+ %hr
+ = f.label :public, class: 'control-label' do
+ Public
+ .col-sm-10
+ .checkbox
+ = f.check_box :public
+ %span.descr Make this group public (even if there is no any public project inside this group)
+
.form-actions
= f.submit 'Save group', class: "btn btn-save"
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index ceb64ce315..d1aa8f6246 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -11,6 +11,8 @@
= hidden_field_tag :scope, 'merge_requests'
- elsif current_controller?(:wikis)
= hidden_field_tag :scope, 'wiki_blobs'
+ - elsif current_controller?(:commits)
+ = hidden_field_tag :scope, 'commits'
- else
= hidden_field_tag :search_code, true
diff --git a/app/views/layouts/ci/project.html.haml b/app/views/layouts/ci/project.html.haml
deleted file mode 100644
index 15478c3f5b..0000000000
--- a/app/views/layouts/ci/project.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 @project.name, ci_project_path(@project)
- - 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/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index eb35af22b9..319352876b 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -1,9 +1,9 @@
%ul.nav.nav-sidebar
= nav_link do
- = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
+ = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to dashboard
+ Go to dashboard
%li.separate-item
diff --git a/app/views/layouts/nav/_group_settings.html.haml b/app/views/layouts/nav/_group_settings.html.haml
index 6609f6b3a4..bb0234cf11 100644
--- a/app/views/layouts/nav/_group_settings.html.haml
+++ b/app/views/layouts/nav/_group_settings.html.haml
@@ -1,9 +1,9 @@
%ul.nav.nav-sidebar
= nav_link do
- = link_to group_path(@group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do
+ = link_to group_path(@group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to group
+ Go to group
%li.separate-item
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index 5a47b8e6db..0f3a793e30 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -1,9 +1,9 @@
%ul.nav.nav-sidebar
= nav_link do
- = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
+ = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to dashboard
+ Go to dashboard
%li.separate-item
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 53a913fe8f..20db2866d1 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -1,16 +1,16 @@
%ul.nav.nav-sidebar
- if @project.group
= nav_link do
- = link_to group_path(@project.group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do
+ = link_to group_path(@project.group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to group
+ Go to group
- else
= nav_link do
- = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
+ = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to dashboard
+ Go to dashboard
%li.separate-item
diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml
index c28dcc4be8..7587caf165 100644
--- a/app/views/layouts/nav/_project_settings.html.haml
+++ b/app/views/layouts/nav/_project_settings.html.haml
@@ -1,9 +1,9 @@
%ul.nav.nav-sidebar
= nav_link do
- = link_to project_path(@project), title: 'Back to project', data: {placement: 'right'}, class: 'back-link' do
+ = link_to project_path(@project), title: 'Go to project', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to project
+ Go to project
%li.separate-item
@@ -81,8 +81,3 @@
= 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/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index 3a8172dc8e..e3d8d73491 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -155,7 +155,7 @@
- if @builds.present?
.build-widget
- %h4.title #{pluralize(@builds.count, "other build")} for #{@build.short_sha}:
+ %h4.title #{pluralize(@builds.count(:id), "other build")} for #{@build.short_sha}:
%table.table.builds
- @builds.each_with_index do |build, i|
%tr.build
diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml
index 4580c91269..bed2b16249 100644
--- a/app/views/projects/buttons/_dropdown.html.haml
+++ b/app/views/projects/buttons/_dropdown.html.haml
@@ -20,6 +20,10 @@
New snippet
- if can?(current_user, :push_code, @project)
%li.divider
+ %li
+ = link_to namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'), title: 'New file' do
+ = icon('file fw')
+ New file
%li
= link_to new_namespace_project_branch_path(@project.namespace, @project) do
= icon('code-fork fw')
diff --git a/app/views/projects/ci_settings/_form.html.haml b/app/views/projects/ci_settings/_form.html.haml
index d711413c6b..20bdccc902 100644
--- a/app/views/projects/ci_settings/_form.html.haml
+++ b/app/views/projects/ci_settings/_form.html.haml
@@ -102,7 +102,7 @@
%code \(\d+.\d+\%\) covered
%li
pytest-cov (Python) -
- %code \d+\%$
+ %code \d+\%\s*$
diff --git a/app/views/projects/ci_settings/_no_runners.html.haml b/app/views/projects/ci_settings/_no_runners.html.haml
index 33038c5297..1374e6680f 100644
--- a/app/views/projects/ci_settings/_no_runners.html.haml
+++ b/app/views/projects/ci_settings/_no_runners.html.haml
@@ -5,4 +5,4 @@
You can add Specific runner for this project on Runners page
- if current_user.admin
- or add Shared runner for whole application in admin are.
+ or add Shared runner for whole application in admin area.
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index cddd5aa3a8..805be332e6 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -18,10 +18,10 @@
.pull-right
- if ci_commit
- = link_to ci_status_path(ci_commit), class: "c#{ci_status_color(ci_commit)}" do
- = ci_status_icon(ci_commit)
+ = render_ci_status(ci_commit)
- = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
+ = clipboard_button
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id", data: {clipboard_text: commit.id}
.notes_count
- if note_count > 0
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index d4a98eca47..c5fd863ae9 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -17,8 +17,10 @@
- @participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
.col-md-3
- %span.slead.has_tooltip{title: 'Cross-project reference'}
- = cross_project_reference(@project, @issue)
+ .input-group.cross-project-reference
+ %span.slead.has_tooltip{title: 'Cross-project reference'}
+ = cross_project_reference(@project, @issue)
+ = clipboard_button
.row
%section.col-md-9
diff --git a/app/views/projects/labels/destroy.js.haml b/app/views/projects/labels/destroy.js.haml
index 1b4c83ab09..d59563b122 100644
--- a/app/views/projects/labels/destroy.js.haml
+++ b/app/views/projects/labels/destroy.js.haml
@@ -1,2 +1,2 @@
- if @project.labels.size == 0
- $('.labels').load(document.URL + ' .light-well').hide().fadeIn(1000)
+ $('.labels').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000)
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 97175f8232..fb784ee5f4 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -14,8 +14,8 @@
= render @labels
= paginate @labels, theme: 'gitlab'
- else
- .light-well
+ .nothing-here-block
- if can? current_user, :admin_label, @project
- .nothing-here-block Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
+ Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
- else
- .nothing-here-block No labels created
+ No labels created
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 25e4e8ba80..300a371529 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -1,3 +1,4 @@
+- ci_commit = merge_request.ci_commit
%li{ class: mr_css_classes(merge_request) }
.merge-request-title
%span.merge-request-title-text
@@ -6,6 +7,8 @@
- merge_request.labels.each do |label|
= link_to_label(label, project: merge_request.project)
.pull-right.light
+ - if ci_commit
+ = render_ci_status(ci_commit)
- if merge_request.merged?
%span
%i.fa.fa-check
diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
index f18cf96c17..98f0357ce4 100644
--- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
@@ -3,11 +3,12 @@
.modal-content
.modal-header
%a.close{href: "#", "data-dismiss" => "modal"} ×
- %h3 Check out, review and merge locally
+ %h3 Check out, review, and merge locally
.modal-body
%p
- %strong Step 1.
+ %strong Step 1.
Fetch and check out the branch for this merge request
+ = clipboard_button
%pre.dark
- if @merge_request.for_fork?
:preserve
@@ -24,6 +25,7 @@
%p
%strong Step 3.
Merge the branch and fix any conflicts that come up
+ = clipboard_button
%pre.dark
- if @merge_request.for_fork?
:preserve
@@ -36,6 +38,7 @@
%p
%strong Step 4.
Push the result of the merge to GitLab
+ = clipboard_button
%pre.dark
:preserve
git push origin #{h @merge_request.target_branch}
diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml
index 10efb81193..a3551516bf 100644
--- a/app/views/projects/merge_requests/widget/_heading.html.haml
+++ b/app/views/projects/merge_requests/widget/_heading.html.haml
@@ -1,4 +1,4 @@
-- ci_commit = @merge_request.source_project.ci_commit(@merge_request.source_sha)
+- ci_commit = @merge_request.ci_commit
- if ci_commit
- status = ci_commit.status
.mr-widget-heading
diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml
index d637abfa76..481451edb2 100644
--- a/app/views/search/_category.html.haml
+++ b/app/views/search/_category.html.haml
@@ -42,6 +42,13 @@
Wiki
%span.badge
= @search_results.wiki_blobs_count
+ %li{class: ("active" if @scope == 'commits')}
+ = link_to search_filter_path(scope: 'commits') do
+ = icon('history fw')
+ %span
+ Commits
+ %span.badge
+ = @search_results.commits_count
- elsif @show_snippets
%li{class: ("active" if @scope == 'snippet_blobs')}
diff --git a/app/views/search/results/_commit.html.haml b/app/views/search/results/_commit.html.haml
new file mode 100644
index 0000000000..4e6c3965dc
--- /dev/null
+++ b/app/views/search/results/_commit.html.haml
@@ -0,0 +1,2 @@
+.search-result-row
+ = render 'projects/commits/commit', project: @project, commit: commit
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index aee839b44e..c36995b94d 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -21,9 +21,7 @@
.project-controls
- if ci && !project.empty_repo? && project.commit
- if ci_commit = project.ci_commit(project.commit.sha)
- = link_to ci_status_path(ci_commit), class: "c#{ci_status_color(ci_commit)}",
- title: "Build status: #{ci_commit.status}", data: {toggle: 'tooltip', placement: 'left'} do
- = ci_status_icon(ci_commit)
+ = render_ci_status(ci_commit)
- if stars
%span
diff --git a/app/views/snippets/_actions.html.haml b/app/views/snippets/_actions.html.haml
index 751fafa894..1979ae6d5b 100644
--- a/app/views/snippets/_actions.html.haml
+++ b/app/views/snippets/_actions.html.haml
@@ -1,11 +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
+- 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
diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml
deleted file mode 100644
index a126a858ea..0000000000
--- a/app/views/users/_projects.html.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-- if local_assigns.has_key?(:contributed_projects) && contributed_projects.present?
- .panel.panel-default.contributed-projects
- .panel-heading Projects contributed to
- = render 'shared/projects/list',
- projects: contributed_projects.sort_by(&:star_count).reverse,
- projects_limit: 5, stars: true, avatar: false
-
-- if local_assigns.has_key?(:projects) && projects.present?
- .panel.panel-default
- .panel-heading Personal projects
- = render 'shared/projects/list',
- projects: projects.sort_by(&:star_count).reverse,
- projects_limit: 10, stars: true, avatar: false
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 4ea4a1f92c..5a15c6c244 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -24,22 +24,27 @@
.cover-desc
- unless @user.public_email.blank?
- = link_to @user.public_email, "mailto:#{@user.public_email}"
+ .profile-link-holder
+ = link_to @user.public_email, "mailto:#{@user.public_email}"
- unless @user.skype.blank?
- ·
- = link_to "Skype", "skype:#{@user.skype}"
+ .profile-link-holder
+ = link_to "skype:#{@user.skype}", title: "Skype" do
+ = icon('skype')
- unless @user.linkedin.blank?
- ·
- = link_to "LinkedIn", "http://www.linkedin.com/in/#{@user.linkedin}"
+ .profile-link-holder
+ = link_to "http://www.linkedin.com/in/#{@user.linkedin}", title: "LinkedIn" do
+ = icon('linkedin-square')
- unless @user.twitter.blank?
- ·
- = link_to "Twitter", "http://www.twitter.com/#{@user.twitter}"
+ .profile-link-holder
+ = link_to "http://www.twitter.com/#{@user.twitter}", title: "Twitter" do
+ = icon('twitter-square')
- unless @user.website_url.blank?
- ·
- = link_to @user.short_website_url, @user.full_website_url
+ .profile-link-holder
+ = link_to @user.short_website_url, @user.full_website_url
- unless @user.location.blank?
- ·
- = @user.location
+ .profile-link-holder
+ = icon('map-marker')
+ = @user.location
.cover-controls
@@ -47,7 +52,7 @@
= link_to profile_path, class: 'btn btn-gray' do
= icon('pencil')
- elsif current_user
- .report-abuse
+ %span.report-abuse
- if @user.abuse_report
%button.btn.btn-danger{ title: 'Already reported for abuse',
data: { toggle: 'tooltip', placement: 'left', container: 'body' }}
@@ -56,6 +61,10 @@
= 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')
+ - if current_user
+
+ = link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do
+ = icon('rss')
.gray-content-block.second-block
.user-calendar
@@ -64,27 +73,47 @@
.user-calendar-activities
-.row.prepend-top-20
- %section.col-md-7
- - if @groups.any?
- .prepend-top-20
- %h4 Groups
- = render 'groups', groups: @groups
- %hr
-
- %h4
- User Activity
-
- - if current_user
- %span.rss-icon.pull-right
- = link_to user_path(@user, :atom, { private_token: current_user.private_token }) do
- %strong
- %i.fa.fa-rss
+%ul.center-middle-menu
+ %li.active
+ = link_to "#activity", 'data-toggle' => 'tab' do
+ Activity
+ - if @groups.any?
+ %li
+ = link_to "#groups", 'data-toggle' => 'tab' do
+ Groups
+ - if @contributed_projects.present?
+ %li
+ = link_to "#contributed", 'data-toggle' => 'tab' do
+ Contributed projects
+ - if @projects.present?
+ %li
+ = link_to "#personal", 'data-toggle' => 'tab' do
+ Personal projects
+.tab-content
+ .tab-pane.active#activity
.content_list
= spinner
- %aside.col-md-5
- = render 'projects', projects: @projects, contributed_projects: @contributed_projects
+
+ - if @groups.any?
+ .tab-pane#groups
+ %ul.content-list
+ - @groups.each do |group|
+ = render 'shared/groups/group', group: group
+
+ - if @contributed_projects.present?
+ .tab-pane#contributed
+ .contributed-projects
+ = render 'shared/projects/list',
+ projects: @contributed_projects.sort_by(&:star_count).reverse,
+ projects_limit: 5, stars: true, avatar: true
+
+ - if @projects.present?
+ .tab-pane#personal
+ .personal-projects
+ = render 'shared/projects/list',
+ projects: @projects.sort_by(&:star_count).reverse,
+ projects_limit: 10, stars: true, avatar: true
:coffeescript
$(".user-calendar").load("#{user_calendar_path}")
diff --git a/app/workers/stuck_ci_builds_worker.rb b/app/workers/stuck_ci_builds_worker.rb
new file mode 100644
index 0000000000..ad02a3b16d
--- /dev/null
+++ b/app/workers/stuck_ci_builds_worker.rb
@@ -0,0 +1,18 @@
+class StuckCiBuildsWorker
+ include Sidekiq::Worker
+ include Sidetiq::Schedulable
+
+ BUILD_STUCK_TIMEOUT = 1.day
+
+ recurrence { daily }
+
+ def perform
+ Rails.logger.info 'Cleaning stuck builds'
+
+ builds = Ci::Build.running_or_pending.where('updated_at < ?', BUILD_STUCK_TIMEOUT.ago)
+ builds.find_each(batch_size: 50).each do |build|
+ Rails.logger.debug "Dropping stuck #{build.status} build #{build.id} for runner #{build.runner_id}"
+ build.drop
+ end
+ end
+end
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 5ad8c055ef..2c4064b85f 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -330,28 +330,29 @@ 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',
- # label: 'Google',
- # app_id: 'YOUR_APP_ID',
- # app_secret: 'YOUR_APP_SECRET',
- # args: { access_type: 'offline', approval_prompt: '' } }
- # - { name: 'twitter',
- # app_id: 'YOUR_APP_ID',
- # app_secret: 'YOUR_APP_SECRET' }
# - { name: 'github',
- # label: 'GitHub',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET',
# url: "https://github.com/",
# args: { scope: 'user:email' } }
- # - { name: 'gitlab',
- # label: 'GitLab.com',
- # app_id: 'YOUR_APP_ID',
- # app_secret: 'YOUR_APP_SECRET',
- # args: { scope: 'api' } }
# - { name: 'bitbucket',
# app_id: 'YOUR_APP_ID',
# app_secret: 'YOUR_APP_SECRET' }
+ # - { name: 'gitlab',
+ # app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET',
+ # args: { scope: 'api' } }
+ # - { name: 'google_oauth2',
+ # app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET',
+ # args: { access_type: 'offline', approval_prompt: '' } }
+ # - { name: 'facebook',
+ # app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET' }
+ # - { name: 'twitter',
+ # app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET' }
+ #
# - { name: 'saml',
# label: 'Our SAML Provider',
# args: {
@@ -367,6 +368,10 @@ production: &base
# application_name: 'YOUR_APP_NAME',
# application_password: 'YOUR_APP_PASSWORD' } }
+ # Shared file storage settings
+ shared:
+ # path: /mnt/gitlab # Default: shared
+
@@ -375,10 +380,12 @@ production: &base
# ==========================
# GitLab Satellites
+ #
+ # Note for maintainers: keep the satellites.path setting until GitLab 9.0 at
+ # least. This setting is fed to 'rm -rf' in
+ # db/migrate/20151023144219_remove_satellites.rb
satellites:
- # Relative paths are relative to Rails.root (default: tmp/repo_satellites/)
path: /home/git/gitlab-satellites/
- timeout: 30
## Backup settings
backup:
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 3df1c408fd..da8978e391 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -153,6 +153,8 @@ if github_settings
end
end
+Settings['shared'] ||= Settingslogic.new({})
+Settings.shared['path'] = File.expand_path(Settings.shared['path'] || "shared", Rails.root)
Settings['issues_tracker'] ||= {}
@@ -198,7 +200,7 @@ Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.g
Settings.gitlab.default_projects_features['wiki'] = true if Settings.gitlab.default_projects_features['wiki'].nil?
Settings.gitlab.default_projects_features['snippets'] = false if Settings.gitlab.default_projects_features['snippets'].nil?
Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE)
-Settings.gitlab['repository_downloads_path'] = File.absolute_path(Settings.gitlab['repository_downloads_path'] || 'tmp/repositories', Rails.root)
+Settings.gitlab['repository_downloads_path'] = File.join(Settings.shared['path'], 'cache/archive') if Settings.gitlab['repository_downloads_path'].nil?
Settings.gitlab['restricted_signup_domains'] ||= []
Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git']
@@ -271,9 +273,12 @@ Settings.git['max_size'] ||= 20971520 # 20.megabytes
Settings.git['bin_path'] ||= '/usr/bin/git'
Settings.git['timeout'] ||= 10
+# Important: keep the satellites.path setting until GitLab 9.0 at
+# least. This setting is fed to 'rm -rf' in
+# db/migrate/20151023144219_remove_satellites.rb
Settings['satellites'] ||= Settingslogic.new({})
Settings.satellites['path'] = File.expand_path(Settings.satellites['path'] || "tmp/repo_satellites/", Rails.root)
-Settings.satellites['timeout'] ||= 30
+
#
# Kerberos
diff --git a/config/initializers/2_app.rb b/config/initializers/2_app.rb
index 688cdf5f4b..35b150c992 100644
--- a/config/initializers/2_app.rb
+++ b/config/initializers/2_app.rb
@@ -1,8 +1,8 @@
module Gitlab
- VERSION = File.read(Rails.root.join("VERSION")).strip
- REVISION = Gitlab::Popen.popen(%W(git log --pretty=format:%h -n 1)).first.chomp
-
def self.config
Settings
end
+
+ VERSION = File.read(Rails.root.join("VERSION")).strip
+ REVISION = Gitlab::Popen.popen(%W(#{config.git.bin_path} log --pretty=format:%h -n 1)).first.chomp
end
diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb
index 5d46ece1e1..9e8b0131f8 100644
--- a/config/initializers/inflections.rb
+++ b/config/initializers/inflections.rb
@@ -8,24 +8,3 @@
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
# end
-
-# Mark "commits" as uncountable.
-#
-# Without this change, the routes
-#
-# resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
-# resources :commits, only: [:show], constraints: {id: /.+/}
-#
-# would generate identical route helper methods (`project_commit_path`), resulting
-# in one of them not getting a helper method at all.
-#
-# After this change, the helper methods are:
-#
-# project_commit_path(@project, @project.commit)
-# # => "/gitlabhq/commit/bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a
-#
-# project_commits_path(@project, 'stable/README.md')
-# # => "/gitlabhq/commits/stable/README.md"
-ActiveSupport::Inflector.inflections do |inflect|
- inflect.uncountable %w(commits)
-end
diff --git a/config/routes.rb b/config/routes.rb
index 4caa1a0969..7a47927b04 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -23,8 +23,6 @@ Gitlab::Application.routes.draw do
end
resources :runner_projects, only: [:create, :destroy]
-
- resources :events, only: [:index]
end
resource :user_sessions do
diff --git a/db/migrate/20151020145526_add_services_template_index.rb b/db/migrate/20151020145526_add_services_template_index.rb
new file mode 100644
index 0000000000..1b04f31356
--- /dev/null
+++ b/db/migrate/20151020145526_add_services_template_index.rb
@@ -0,0 +1,5 @@
+class AddServicesTemplateIndex < ActiveRecord::Migration
+ def change
+ add_index :services, :template
+ end
+end
diff --git a/db/migrate/20151023112551_fail_build_with_empty_name.rb b/db/migrate/20151023112551_fail_build_with_empty_name.rb
new file mode 100644
index 0000000000..f069bc60ac
--- /dev/null
+++ b/db/migrate/20151023112551_fail_build_with_empty_name.rb
@@ -0,0 +1,5 @@
+class FailBuildWithEmptyName < ActiveRecord::Migration
+ def change
+ execute("UPDATE ci_builds SET status='failed' WHERE (name IS NULL OR name='') AND status='pending'")
+ end
+end
diff --git a/db/migrate/20151023144219_remove_satellites.rb b/db/migrate/20151023144219_remove_satellites.rb
new file mode 100644
index 0000000000..e73f300028
--- /dev/null
+++ b/db/migrate/20151023144219_remove_satellites.rb
@@ -0,0 +1,17 @@
+require 'fileutils'
+
+class RemoveSatellites < ActiveRecord::Migration
+ def up
+ satellites = Gitlab.config['satellites']
+ return if satellites.nil?
+
+ satellites_path = satellites['path']
+ return if satellites_path.nil?
+
+ FileUtils.rm_rf(satellites_path)
+ end
+
+ def down
+ # Do nothing
+ end
+end
diff --git a/db/migrate/20151026182941_add_project_path_index.rb b/db/migrate/20151026182941_add_project_path_index.rb
new file mode 100644
index 0000000000..a62fe199d7
--- /dev/null
+++ b/db/migrate/20151026182941_add_project_path_index.rb
@@ -0,0 +1,9 @@
+class AddProjectPathIndex < ActiveRecord::Migration
+ def up
+ add_index :projects, :path
+ end
+
+ def down
+ remove_index :projects, :path
+ end
+end
diff --git a/db/migrate/20151103001141_add_public_to_group.rb b/db/migrate/20151103001141_add_public_to_group.rb
new file mode 100644
index 0000000000..635346300c
--- /dev/null
+++ b/db/migrate/20151103001141_add_public_to_group.rb
@@ -0,0 +1,5 @@
+class AddPublicToGroup < ActiveRecord::Migration
+ def change
+ add_column :namespaces, :public, :boolean, default: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 29b7b2cf42..fac0489013 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: 20151020173906) do
+ActiveRecord::Schema.define(version: 20151103001141) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -578,6 +578,7 @@ ActiveRecord::Schema.define(version: 20151020173906) do
t.string "avatar"
t.boolean "membership_lock", default: false
t.boolean "share_with_group_lock", default: false
+ t.boolean "public", default: false
end
add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree
@@ -707,6 +708,7 @@ ActiveRecord::Schema.define(version: 20151020173906) do
add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree
add_index "projects", ["last_activity_at"], name: "index_projects_on_last_activity_at", using: :btree
add_index "projects", ["namespace_id"], name: "index_projects_on_namespace_id", using: :btree
+ add_index "projects", ["path"], name: "index_projects_on_path", using: :btree
add_index "projects", ["star_count"], name: "index_projects_on_star_count", using: :btree
create_table "protected_branches", force: true do |t|
@@ -749,6 +751,7 @@ ActiveRecord::Schema.define(version: 20151020173906) do
add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
+ add_index "services", ["template"], name: "index_services_on_template", using: :btree
create_table "snippets", force: true do |t|
t.string "title"
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index 25311b0710..623063f357 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -23,7 +23,8 @@ Example response:
"content": "IyA9PSBTY2hlbWEgSW5mb3...",
"ref": "master",
"blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
- "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50"
+ "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50",
+ "last_commit_id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d"
}
```
diff --git a/doc/ci/api/README.md b/doc/ci/api/README.md
index 33c5b172e9..cf9710ede5 100644
--- a/doc/ci/api/README.md
+++ b/doc/ci/api/README.md
@@ -25,7 +25,7 @@ GitLab CI API has 4 authentication methods:
Authentication is done by
sending the `private-token` of a valid user and the `url` of an
-authorized Gitlab instance via a query string along with the API
+authorized GitLab instance via a query string along with the API
request:
GET http://gitlab.example.com/ci/api/v1/projects?private_token=QVy1PB7sTxfy4pqfZM1U&url=http://demo.gitlab.com/
diff --git a/doc/ci/api/projects.md b/doc/ci/api/projects.md
index 5585191e82..74a4c64d00 100644
--- a/doc/ci/api/projects.md
+++ b/doc/ci/api/projects.md
@@ -1,7 +1,7 @@
# Projects API
This API is intended to aid in the setup and configuration of
-projects on Gitlab CI.
+projects on GitLab CI.
__Authentication is done by GitLab user token & GitLab url__
@@ -88,23 +88,23 @@ authorized.
Parameters:
- * `id` (required) - The ID of the Gitlab CI project
+ * `id` (required) - The ID of the GitLab CI project
### Create Project
-Creates a Gitlab CI project using Gitlab project details.
+Creates a GitLab CI project using GitLab project details.
POST /ci/projects
Parameters:
* `name` (required) - The name of the project
- * `gitlab_id` (required) - The ID of the project on the Gitlab instance
+ * `gitlab_id` (required) - The ID of the project on the GitLab instance
* `default_ref` (optional) - The branch to run on (default to `master`)
### Update Project
-Updates a Gitlab CI project using Gitlab project details that the
+Updates a GitLab CI project using GitLab project details that the
authenticated user has access to.
PUT /ci/projects/:id
@@ -116,13 +116,13 @@ Parameters:
### Remove Project
-Removes a Gitlab CI project that the authenticated user has access to.
+Removes a GitLab CI project that the authenticated user has access to.
DELETE /ci/projects/:id
Parameters:
- * `id` (required) - The ID of the Gitlab CI project
+ * `id` (required) - The ID of the GitLab CI project
### Link Project to Runner
@@ -133,8 +133,8 @@ authorized user).
Parameters:
- * `id` (required) - The ID of the Gitlab CI project
- * `runner_id` (required) - The ID of the Gitlab CI runner
+ * `id` (required) - The ID of the GitLab CI project
+ * `runner_id` (required) - The ID of the GitLab CI runner
### Remove Project from Runner
@@ -145,5 +145,5 @@ via authorized user).
Parameters:
- * `id` (required) - The ID of the Gitlab CI project
- * `runner_id` (required) - The ID of the Gitlab CI runner
\ No newline at end of file
+ * `id` (required) - The ID of the GitLab CI project
+ * `runner_id` (required) - The ID of the GitLab CI runner
\ No newline at end of file
diff --git a/doc/ci/api/runners.md b/doc/ci/api/runners.md
index e9f88ee066..c383dc4bcc 100644
--- a/doc/ci/api/runners.md
+++ b/doc/ci/api/runners.md
@@ -6,7 +6,7 @@
__Authentication is done by GitLab user token & GitLab url__
-Used to get information about all runners registered on the Gitlab CI
+Used to get information about all runners registered on the GitLab CI
instance.
GET /ci/runners
@@ -31,7 +31,7 @@ Returns:
__Authentication is done with a Shared runner registration token or a project Specific runner registration token__
-Used to make Gitlab CI aware of available runners.
+Used to make GitLab CI aware of available runners.
POST /ci/runners/register
diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md
index e0b9fa0e25..1cf41aea39 100644
--- a/doc/ci/examples/README.md
+++ b/doc/ci/examples/README.md
@@ -1,5 +1,5 @@
# Build script examples
-+ [Test and deploy Ruby Application to Heroku](test-and-deploy-ruby-application-to-heroku.md)
-+ [Test and deploy Python Application to Heroku](test-and-deploy-python-application-to-heroku.md)
-+ [Test Clojure applications](examples/test-clojure-application.md)
++ [Test and deploy a Ruby application to Heroku](test-and-deploy-ruby-application-to-heroku.md)
++ [Test and deploy a Python application to Heroku](test-and-deploy-python-application-to-heroku.md)
++ [Test a Clojure application](test-clojure-application.md)
diff --git a/doc/ci/examples/test-and-deploy-python-application-to-heroku.md b/doc/ci/examples/test-and-deploy-python-application-to-heroku.md
index 036b03dd6b..a236da53fe 100644
--- a/doc/ci/examples/test-and-deploy-python-application-to-heroku.md
+++ b/doc/ci/examples/test-and-deploy-python-application-to-heroku.md
@@ -1,7 +1,7 @@
## Test and Deploy a python application
This example will guide you how to run tests in your Python application and deploy it automatically as Heroku application.
-You can checkout the example [source](https://gitlab.com/ayufan/python-getting-started) and check [CI status](https://ci.gitlab.com/projects/4080).
+You can checkout the example [source](https://gitlab.com/ayufan/python-getting-started) and check [CI status](https://gitlab.com/ayufan/python-getting-started/builds?scope=all).
### Configure project
This is what the `.gitlab-ci.yml` file looks like for this project:
diff --git a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
index d2a872f193..e52e154746 100644
--- a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
+++ b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md
@@ -1,7 +1,7 @@
## Test and Deploy a ruby application
This example will guide you how to run tests in your Ruby application and deploy it automatiacally as Heroku application.
-You can checkout the example [source](https://gitlab.com/ayufan/ruby-getting-started) and check [CI status](https://ci.gitlab.com/projects/4050).
+You can checkout the example [source](https://gitlab.com/ayufan/ruby-getting-started) and check [CI status](https://gitlab.com/ayufan/ruby-getting-started/builds?scope=all).
### Configure project
This is what the `.gitlab-ci.yml` file looks like for this project:
@@ -64,4 +64,4 @@ gitlab-ci-multi-runner register \
With the command above, you create a runner that uses [ruby:2.1](https://registry.hub.docker.com/u/library/ruby/) image and uses [postgres](https://registry.hub.docker.com/u/library/postgres/) database.
-To access PostgreSQL database you need to connect to `host: postgres` as user `postgres` without password.
\ No newline at end of file
+To access PostgreSQL database you need to connect to `host: postgres` as user `postgres` without password.
diff --git a/doc/ci/examples/test-clojure-application.md b/doc/ci/examples/test-clojure-application.md
index eaee94a10f..56b746ce02 100644
--- a/doc/ci/examples/test-clojure-application.md
+++ b/doc/ci/examples/test-clojure-application.md
@@ -1,8 +1,8 @@
-## Test Clojure applications
+## Test a Clojure application
This example will guide you how to run tests in your Clojure application.
-You can checkout the example [source](https://gitlab.com/dzaporozhets/clojure-web-application) and check [CI status](https://ci.gitlab.com/projects/6306).
+You can checkout the example [source](https://gitlab.com/dzaporozhets/clojure-web-application) and check [CI status](https://gitlab.com/dzaporozhets/clojure-web-application/builds?scope=all).
### Configure project
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index ea8f72bc13..d117a2969b 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -169,7 +169,7 @@ This are two parameters that allow for setting a refs policy to limit when jobs
There are a few rules that apply to usage of refs policy:
-1. `only` and `except` are exclusive. If both `only` and `except` are defined in job specification only `only` is taken into account.
+1. `only` and `except` are inclusive. If both `only` and `except` are defined in job specification the ref is filtered by `only` and `except`.
1. `only` and `except` allow for using the regexp expressions.
1. `only` and `except` allow for using special keywords: `branches` and `tags`.
These names can be used for example to exclude all tags and all branches.
@@ -182,6 +182,18 @@ job:
- branches # use special keyword
```
+1. `only` and `except` allow for specify repository path to filter jobs for forks.
+The repository path can be used to have jobs executed only for parent repository.
+
+```yaml
+job:
+ only:
+ - branches@gitlab-org/gitlab-ce
+ except:
+ - master@gitlab-org/gitlab-ce
+```
+The above will run `job` for all branches on `gitlab-org/gitlab-ce`, except master .
+
### tags
`tags` is used to select specific runners from the list of all runners that are allowed to run this project.
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index a4a980cf0e..9f3fd69fc4 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -9,7 +9,7 @@ bundle exec rake setup
```
The `setup` task is a alias for `gitlab:setup`.
-This tasks calls `db:setup` to create the database, calls `add_limits_mysql` that adds limits to the database schema in case of a MySQL database and fianlly it calls `db:seed_fu` to seed the database.
+This tasks calls `db:setup` to create the database, calls `add_limits_mysql` that adds limits to the database schema in case of a MySQL database and finally it calls `db:seed_fu` to seed the database.
Note: `db:setup` calls `db:seed` but this does nothing.
## Run tests
diff --git a/doc/development/shared_files.md b/doc/development/shared_files.md
new file mode 100644
index 0000000000..fcd905b54a
--- /dev/null
+++ b/doc/development/shared_files.md
@@ -0,0 +1,33 @@
+# Shared files
+
+Historically, GitLab has been storing shared files in many different
+directories: `public/uploads`, `builds`, `tmp/repositories`, `tmp/rebase` (EE),
+etc. Having so many shared directories makes it difficult to deploy GitLab on
+shared storage (e.g. NFS). Working towards GitLab 9.0 we are consolidating
+these different directories under the `shared` directory.
+
+This means that if GitLab will start storing puppies in some future version
+then we should put them in `shared/puppies`. Temporary puppy files should be
+stored in `shared/tmp`.
+
+In the GitLab application code you can get the full path to the `shared`
+directory with `Gitlab.config.shared.path`.
+
+## What is not a 'shared file'
+
+Files that belong to only one process, or on only one server, should not go in
+`shared`. Examples include PID files and sockets.
+
+## Temporary files and shared storage
+
+Sometimes you create a temporary file on disk with the intention of it becoming
+'official'. For example you might be first streaming an upload from a user to
+disk in a temporary file so you can perform some checks on it. When the checks
+pass, you make the file official. In scenarios like this please follow these
+rules:
+
+- Store the temporary file under `shared/tmp`, i.e. on the same filesystem you
+ want the official file to be on.
+- Use move/rename operations when operating on the file instead of copy
+ operations where possible, because renaming a file is much faster than
+ copying it.
diff --git a/doc/development/shell_commands.md b/doc/development/shell_commands.md
index 2d1d0fb415..65cdd74bdb 100644
--- a/doc/development/shell_commands.md
+++ b/doc/development/shell_commands.md
@@ -35,6 +35,16 @@ Gitlab::Popen.popen(%W(find /some/path -not -path /some/path -mmin +120 -delete)
This coding style could have prevented CVE-2013-4490.
+## Always use the configurable git binary path for git commands
+
+```ruby
+# Wrong
+system(*%W(git branch -d -- #{branch_name}))
+
+# Correct
+system(*%W(#{Gitlab.config.git.bin_path} branch -d -- #{branch_name}))
+```
+
## Bypass the shell by splitting commands into separate tokens
When we pass shell commands as a single string to Ruby, Ruby will let `/bin/sh` evaluate the entire string. Essentially, we are asking the shell to evaluate a one-line script. This creates a risk for shell injection attacks. It is better to split the shell command into tokens ourselves. Sometimes we use the scripting capabilities of the shell to change the working directory or set environment variables. All of this can also be achieved securely straight from Ruby
@@ -81,9 +91,9 @@ In the GitLab codebase, we avoid the option/argument ambiguity by _always_ using
```ruby
# Wrong
-system(*%W(git branch -d #{branch_name}))
+system(*%W(#{Gitlab.config.git.bin_path} branch -d #{branch_name}))
# Correct
-system(*%W(git branch -d -- #{branch_name}))
+system(*%W(#{Gitlab.config.git.bin_path} branch -d -- #{branch_name}))
```
This coding style could have prevented CVE-2013-4582.
@@ -94,9 +104,9 @@ Capturing the output of shell commands with backticks reads nicely, but you are
```ruby
# Wrong
-logs = `cd #{repo_dir} && git log`
+logs = `cd #{repo_dir} && #{Gitlab.config.git.bin_path} log`
# Correct
-logs, exit_status = Gitlab::Popen.popen(%W(git log), repo_dir)
+logs, exit_status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} log), repo_dir)
# Wrong
user = `whoami`
@@ -108,7 +118,7 @@ In other repositories, such as gitlab-shell you can also use `IO.popen`.
```ruby
# Safe IO.popen example
-logs = IO.popen(%W(git log), chdir: repo_dir) { |p| p.read }
+logs = IO.popen(%W(#{Gitlab.config.git.bin_path} log), chdir: repo_dir) { |p| p.read }
```
Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index d198c830b7..5562807860 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -310,7 +310,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
GitLab Shell is an SSH access and repository management software developed specially for GitLab.
# Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
- sudo -u git -H bundle exec rake gitlab:shell:install[v2.6.5] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
+ sudo -u git -H bundle exec rake gitlab:shell:install[v2.6.6] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
# By default, the gitlab-shell config is generated from your main GitLab config.
# You can review (and modify) the gitlab-shell config as follows:
@@ -329,6 +329,10 @@ GitLab Shell is an SSH access and repository management software developed speci
sudo -u git -H make
### Initialize Database and Activate Advanced Features
+
+ # Go to Gitlab installation folder
+
+ cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
@@ -346,11 +350,6 @@ The `secrets.yml` file stores encryption keys for sessions and secure variables.
Backup `secrets.yml` someplace safe, but don't store it in the same place as your database backups.
Otherwise your secrets are exposed if one of your backups is compromised.
-### Install schedules
-
- # Setup schedules
- sudo -u gitlab_ci -H bundle exec whenever -w RAILS_ENV=production
-
### Install Init Script
Download the init script (will be `/etc/init.d/gitlab`):
@@ -494,7 +493,7 @@ See the [omniauth integration document](../integration/omniauth.md)
### Build your projects
GitLab can build your projects. To enable that feature you need GitLab Runners to do that for you.
-Checkout the [Gitlab Runner section](https://about.gitlab.com/gitlab-ci/#gitlab-runner) to install it
+Checkout the [GitLab Runner section](https://about.gitlab.com/gitlab-ci/#gitlab-runner) to install it
### Custom Redis Connection
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index aa0d03b75b..c0ccdd3745 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -109,8 +109,4 @@ On a very active server (10,000 active users) the Sidekiq process can use 1GB+ o
- Firefox (Latest released version and [latest ESR version](https://www.mozilla.org/en-US/firefox/organizations/))
- Safari 7+ (known problem: required fields in html5 do not work)
- Opera (Latest released version)
-- IE 10+
-
-### Common UI problems with IE
-
-If you experience UI issues with Internet Explorer, please make sure that you have the `Compatibility View` mode disabled.
\ No newline at end of file
+- Internet Explorer (IE) 10+ but please make sure that you have the `Compatibility View` mode disabled.
\ No newline at end of file
diff --git a/doc/integration/facebook.md b/doc/integration/facebook.md
new file mode 100644
index 0000000000..bc1f167308
--- /dev/null
+++ b/doc/integration/facebook.md
@@ -0,0 +1,97 @@
+# Facebook OAuth2 OmniAuth Provider
+
+To enable the Facebook OmniAuth provider you must register your application with Facebook. Facebook will generate an app ID and secret key for you to use.
+
+1. Sign in to the [Facebook Developer Platform](https://developers.facebook.com/).
+
+1. Choose "My Apps" > "Add a New App"
+
+1. Select the type "Website"
+
+1. Enter a name for your app. This can be anything. Consider something like "<Organization>'s GitLab" or "<Your Name>'s GitLab" or
+something else descriptive.
+
+1. Choose "Create New Facebook App ID"
+
+1. Select a Category, for example "Productivity"
+
+1. Choose "Create App ID"
+
+1. Enter the address of your GitLab installation at the bottom of the package
+
+ 
+
+1. Choose "Next"
+
+1. Choose "Skip Quick Start" in the upper right corner
+
+1. Choose "Settings" in the menu on the left
+
+1. Fill in a contact email for your app
+
+ 
+
+1. Choose "Save Changes"
+
+1. Choose "Status & Review" in the menu on the left
+
+1. Change the switch on the right from No to Yes
+
+1. Choose "Confirm" when prompted to make the app public
+
+1. Choose "Dashboard" in the menu on the left
+
+1. Choose "Show" next to the hidden "App Secret"
+
+1. You should now see an app key and app secret (see screenshot). Keep this page open as you continue configuration.
+
+ 
+
+1. On your GitLab server, open the configuration file.
+
+ For omnibus package:
+
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
+
+ For installations from source:
+
+ ```sh
+ cd /home/git/gitlab
+
+ sudo -u git -H editor config/gitlab.yml
+ ```
+
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1. Add the provider configuration:
+
+ For omnibus package:
+
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "facebook",
+ "app_id" => "YOUR_APP_ID",
+ "app_secret" => "YOUR_APP_SECRET"
+ }
+ ]
+ ```
+
+ For installations from source:
+
+ ```
+ - { name: 'facebook', app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET' }
+ ```
+
+1. Change 'YOUR_APP_ID' to the API key from Facebook page in step 10.
+
+1. Change 'YOUR_APP_SECRET' to the API secret from the Facebook page in step 10.
+
+1. Save the configuration file.
+
+1. Restart GitLab for the changes to take effect.
+
+On the sign in page there should now be a Facebook icon below the regular sign in form. Click the icon to begin the authentication process. Facebook will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in.
diff --git a/doc/integration/facebook_api_keys.png b/doc/integration/facebook_api_keys.png
new file mode 100644
index 0000000000..d6c44ac0f1
Binary files /dev/null and b/doc/integration/facebook_api_keys.png differ
diff --git a/doc/integration/facebook_app_settings.png b/doc/integration/facebook_app_settings.png
new file mode 100644
index 0000000000..30dd21e198
Binary files /dev/null and b/doc/integration/facebook_app_settings.png differ
diff --git a/doc/integration/facebook_website_url.png b/doc/integration/facebook_website_url.png
new file mode 100644
index 0000000000..dc3088bb2f
Binary files /dev/null and b/doc/integration/facebook_website_url.png differ
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index c5cecbc2f2..bd9550c6dd 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -73,8 +73,9 @@ Now we can choose one or more of the Supported Providers below to continue confi
- [Bitbucket](bitbucket.md)
- [GitLab.com](gitlab.md)
- [Google](google.md)
-- [Shibboleth](shibboleth.md)
+- [Facebook](facebook.md)
- [Twitter](twitter.md)
+- [Shibboleth](shibboleth.md)
- [SAML](saml.md)
- [Crowd](crowd.md)
diff --git a/doc/operations/unicorn.md b/doc/operations/unicorn.md
index 31b432cd41..3998da01f0 100644
--- a/doc/operations/unicorn.md
+++ b/doc/operations/unicorn.md
@@ -78,7 +78,7 @@ threshold is a random value between 200 and 250 MB. The master process (PID
```
One other thing that stands out in the log snippet above, taken from
-Gitlab.com, is that 'worker 4' was serving requests for only 23 seconds. This
+GitLab.com, is that 'worker 4' was serving requests for only 23 seconds. This
is a normal value for our current GitLab.com setup and traffic.
The high frequency of Unicorn memory restarts on some GitLab sites can be a
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index 7a6a195844..8d4c2ceab7 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -15,8 +15,8 @@ documentation](doc/workflow/add-user/add-user.md).
|---------------------------------------|---------|------------|-------------|----------|--------|
| Create new issue | ✓ | ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Pull project code | | ✓ | ✓ | ✓ | ✓ |
-| Download project | | ✓ | ✓ | ✓ | ✓ |
+| Pull project code | ✓ | ✓ | ✓ | ✓ | ✓ |
+| Download project | ✓ | ✓ | ✓ | ✓ | ✓ |
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 06f582dcee..606532a6fb 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -29,7 +29,7 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
Also you can choose what should be backed up by adding environment variable SKIP. Available options: db,
-uploads (attachments), repositories. Use a comma to specify several options at the same time.
+uploads (attachments), repositories, builds(CI build output logs). Use a comma to specify several options at the same time.
```
sudo gitlab-rake gitlab:backup:create SKIP=db,uploads
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index b6b8000af4..0bdb4070e7 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -15,8 +15,7 @@ Note: It is a best practice to use a password for an SSH key, but it is not
required and you can skip creating a password by pressing enter. Note that
the password you choose here can't be altered or retrieved.
-To generate a new SSH key, use the following command:
-```bash
+To generate a new SSH key, use the following commandGitLab```bash
ssh-keygen -t rsa -C "$your_email"
```
This command will prompt you for a location and filename to store the key
@@ -82,7 +81,7 @@ How to add your ssh key to Eclipse: http://wiki.eclipse.org/EGit/User_Guide#Ecli
## Tip: Non-default OpenSSH key file names or locations
-If, for whatever reason, you decide to specify a non-default location and filename for your Gitlab SSH key pair, you must configure your SSH client to find your Gitlab SSH private key for connections to your Gitlab server (perhaps gitlab.com). For OpenSSH clients, this is handled in the `~/.ssh/config` file with a stanza similar to the following:
+If, for whatever reason, you decide to specify a non-default location and filename for your GitLab SSH key pair, you must configure your SSH client to find your GitLab SSH private key for connections to your GitLab server (perhaps gitlab.com). For OpenSSH clients, this is handled in the `~/.ssh/config` file with a stanza similar to the following:
```
#
@@ -97,7 +96,7 @@ User mygitlabusername
Another example
```
#
-# Our company's internal Gitlab server
+# Our company's internal GitLab server
#
Host my-gitlab.company.com
RSAAuthentication yes
diff --git a/doc/update/8.1-to-8.2.md b/doc/update/8.1-to-8.2.md
new file mode 100644
index 0000000000..3772f624e9
--- /dev/null
+++ b/doc/update/8.1-to-8.2.md
@@ -0,0 +1,188 @@
+# From 8.1 to 8.2
+
+**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-2-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 8-2-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. Replace gitlab-git-http-server with gitlab-workhorse
+
+Install and compile gitlab-workhorse. This requires [Go
+1.5](https://golang.org/dl) which should already be on your system
+from GitLab 8.1.
+
+```bash
+cd /home/git
+sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
+cd gitlab-workhorse
+sudo -u git -H git checkout 0.3.1
+sudo -u git -H make
+```
+
+Update the GitLab init script and 'default' file.
+
+```
+cd /home/git/gitlab
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+test -e /etc/default/gitlab && \
+ sudo sed -i.pre-8.2 's/^\([^=]*\)gitlab_git_http_server/\1gitlab_workhorse/' /etc/default/gitlab
+```
+
+Make sure that you also update your **NGINX configuration** to use
+the new gitlab-workhorse.socket file.
+
+### 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-1-stable:config/gitlab.yml.example origin/8-2-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-1-stable:lib/support/nginx/gitlab-ssl origin/8-2-stable:lib/support/nginx/gitlab-ssl
+
+# For HTTP configurations
+git diff origin/8-1-stable:lib/support/nginx/gitlab origin/8-2-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-2-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/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index 62c647520e..8d2936a22c 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -73,7 +73,10 @@ X-Gitlab-Event: Push Hook
}
}
],
- "total_commits_count": 4
+ "total_commits_count": 4,
+ "added": ["CHANGELOG"],
+ "modified": ["app/controller/application.rb"],
+ "removed": []
}
```
diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md
index 2d9fe4ad01..6fc688bff6 100644
--- a/doc/workflow/gitlab_flow.md
+++ b/doc/workflow/gitlab_flow.md
@@ -26,7 +26,7 @@ After getting used to these three steps the branching model becomes the challeng
Since many organizations new to git have no conventions how to work with it, it can quickly become a mess.
The biggest problem they run into is that many long running branches that each contain part of the changes are around.
People have a hard time figuring out which branch they should develop on or deploy to production.
-Frequently the reaction to this problem is to adopt a standardized pattern such as [git flow](http://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html)
+Frequently the reaction to this problem is to adopt a standardized pattern such as [git flow](http://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html).
We think there is still room for improvement and will detail a set of practices we call GitLab flow.
## Git flow and its problems
diff --git a/doc/workflow/importing/import_projects_from_gitlab_com.md b/doc/workflow/importing/import_projects_from_gitlab_com.md
index f4c4e955d4..1117db98e7 100644
--- a/doc/workflow/importing/import_projects_from_gitlab_com.md
+++ b/doc/workflow/importing/import_projects_from_gitlab_com.md
@@ -2,12 +2,12 @@
You can import your existing GitLab.com projects to your GitLab instance. But keep in mind that it is possible only if
GitLab support is enabled on your GitLab instance.
-You can read more about Gitlab support [here](http://doc.gitlab.com/ce/integration/gitlab.html)
+You can read more about GitLab support [here](http://doc.gitlab.com/ce/integration/gitlab.html)
To get to the importer page you need to go to "New project" page.

-Click on the "Import projects from Gitlab.com" link and you will be redirected to GitLab.com
+Click on the "Import projects from GitLab.com" link and you will be redirected to GitLab.com
for permission to access your projects. After accepting, you'll be automatically redirected to the importer.
diff --git a/doc_styleguide.md b/doc_styleguide.md
index 656bb1d17f..cceb449a85 100644
--- a/doc_styleguide.md
+++ b/doc_styleguide.md
@@ -15,6 +15,8 @@ For subtitles, use '##', '###' and so on.
- Do not duplicate information.
- Be brief and clear.
- Whenever it applies, add documents in alphabetical order.
+- Write in US English
+- Use [single spaces](http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html) instead of double spaces.
## Images
diff --git a/features/profile/profile.feature b/features/profile/profile.feature
index 27c0bde364..168d9d30b5 100644
--- a/features/profile/profile.feature
+++ b/features/profile/profile.feature
@@ -7,6 +7,7 @@ Feature: Profile
Given I visit profile page
Then I should see my profile info
+ @javascript
Scenario: I can see groups I belong to
Given I have group with projects
When I visit profile page
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 61976f5490..79a6f7de4d 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -10,6 +10,12 @@ Feature: Project Merge Requests
Then I should see "Bug NS-04" in merge requests
And I should not see "Feature NS-03" in merge requests
+ Scenario: I should see CI status for merge requests
+ Given project "Shop" have "Bug NS-05" open merge request with diffs inside
+ Given "Bug NS-05" has CI status
+ When I visit project "Shop" merge requests page
+ Then I should see merge request "Bug NS-05" with CI status
+
Scenario: I should see rejected merge requests
Given I click link "Closed"
Then I should see "Feature NS-03" in merge requests
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index 6b0484b6a3..69aa79f2d2 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -90,6 +90,16 @@ Feature: Project Source Browse Files
Then I am on the new file page
And I see a commit error message
+ @javascript
+ Scenario: I can create file with a directory name
+ Given I click on "New file" link in repo
+ And I fill the new file name with a new directory
+ And I edit code
+ And I fill the commit message
+ And I click on "Commit changes"
+ Then I am redirected to the new file with directory
+ And I should see its new content
+
@javascript
Scenario: I can edit file
Given I click on ".gitignore" file in repo
diff --git a/features/steps/group_active_tab.rb b/features/steps/group_active_tab.rb
index df57e9e247..eaae67dbcb 100644
--- a/features/steps/group_active_tab.rb
+++ b/features/steps/group_active_tab.rb
@@ -11,7 +11,7 @@ class Spinach::Features::GroupActiveTab < Spinach::FeatureSteps
step 'the active main tab should be Settings' do
page.within '.nav-sidebar' do
- expect(page).to have_content('Back to group')
+ expect(page).to have_content('Go to group')
end
end
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index 5a372c2977..42372f4e32 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -6,7 +6,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
include Select2Helper
step 'I should see back to dashboard button' do
- expect(page).to have_content 'Back to dashboard'
+ expect(page).to have_content 'Go to dashboard'
end
step 'gitlab user "Mike"' do
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index 8cf24705a5..40b2aa7c35 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -59,7 +59,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
step 'I should not see the "Remove avatar" button' do
expect(page).not_to have_link("Remove avatar")
end
-
+
step 'I should see the gravatar host link' do
expect(page).to have_link("gravatar.com")
end
@@ -159,10 +159,9 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
end
step 'I should see my user page' do
- expect(page).to have_content "User Activity"
-
- page.within '.navbar-gitlab' do
+ page.within ".cover-block" do
expect(page).to have_content current_user.name
+ expect(page).to have_content current_user.username
end
end
@@ -176,7 +175,13 @@ class Spinach::Features::Profile < Spinach::FeatureSteps
end
step 'I should see groups I belong to' do
- expect(page).to have_css('.profile-groups-avatars', visible: true)
+ page.within ".content" do
+ click_link "Groups"
+ end
+
+ page.within "#groups" do
+ expect(page).to have_content @group.name
+ end
end
step 'I click on new application button' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 29817c7967..7364d236d3 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -460,6 +460,19 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
login_with user
end
+ step '"Bug NS-05" has CI status' do
+ project = merge_request.source_project
+ project.enable_ci
+ ci_commit = create :ci_commit, gl_project: project, sha: merge_request.last_commit.id
+ create :ci_build, commit: ci_commit
+ end
+
+ step 'I should see merge request "Bug NS-05" with CI status' do
+ page.within ".mr-list" do
+ expect(page).to have_link "Build status: pending"
+ end
+ end
+
def merge_request
@merge_request ||= MergeRequest.find_by!(title: "Bug NS-05")
end
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index 5dafc9fc64..893968fa31 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -157,11 +157,11 @@ class Spinach::Features::Project < Spinach::FeatureSteps
end
step 'I should see back to dashboard button' do
- expect(page).to have_content 'Back to dashboard'
+ expect(page).to have_content 'Go to dashboard'
end
step 'I should see back to group button' do
- expect(page).to have_content 'Back to group'
+ expect(page).to have_content 'Go to group'
end
step 'I click notifications drop down button' do
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 1b27500497..84725b9b58 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -78,6 +78,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
fill_in :file_name, with: 'Spaces Not Allowed'
end
+ step 'I fill the new file name with a new directory' do
+ fill_in :file_name, with: new_file_name_with_directory
+ end
+
step 'I fill the commit message' do
fill_in :commit_message, with: 'Not yet a commit message.', visible: true
end
@@ -238,6 +242,11 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
@project.namespace, @project, 'master/' + new_file_name))
end
+ step 'I am redirected to the new file with directory' do
+ expect(current_path).to eq(namespace_project_blob_path(
+ @project.namespace, @project, 'master/' + new_file_name_with_directory))
+ end
+
step 'I am redirected to the new file on new branch' do
expect(current_path).to eq(namespace_project_blob_path(
@project.namespace, @project, 'new_branch_name/' + new_file_name))
@@ -335,6 +344,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
'not_a_file.md'
end
+ # Constant value that is a valid filename with directory and
+ # not a filename present at root of the seed repository.
+ def new_file_name_with_directory
+ 'foo/bar/baz.txt'
+ end
+
# Constant value that is a valid directory and
# not a directory present at root of the seed repository.
def new_dir_name
diff --git a/features/steps/shared/project_tab.rb b/features/steps/shared/project_tab.rb
index c67e5e4a06..33ff7084e3 100644
--- a/features/steps/shared/project_tab.rb
+++ b/features/steps/shared/project_tab.rb
@@ -46,7 +46,7 @@ module SharedProjectTab
step 'the active main tab should be Settings' do
page.within '.nav-sidebar' do
- expect(page).to have_content('Back to project')
+ expect(page).to have_content('Go to project')
end
end
diff --git a/lib/api/files.rb b/lib/api/files.rb
index 308c84dd13..a7a768f889 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -43,7 +43,8 @@ module API
# "content": "IyA9PSBTY2hlbWEgSW5mb3...",
# "ref": "master",
# "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
- # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50"
+ # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50",
+ # "last_commit_id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
# }
#
get ":id/repository/files" do
@@ -71,6 +72,7 @@ module API
ref: ref,
blob_id: blob.id,
commit_id: commit.id,
+ last_commit_id: user_project.repository.last_commit_for_path(commit.sha, file_path).id
}
else
not_found! 'File'
diff --git a/lib/backup/builds.rb b/lib/backup/builds.rb
index 6f56f680bb..635967f4bd 100644
--- a/lib/backup/builds.rb
+++ b/lib/backup/builds.rb
@@ -1,34 +1,13 @@
+require 'backup/files'
+
module Backup
- class Builds
- attr_reader :app_builds_dir, :backup_builds_dir, :backup_dir
-
+ class Builds < Files
def initialize
- @app_builds_dir = Settings.gitlab_ci.builds_path
- @backup_dir = Gitlab.config.backup.path
- @backup_builds_dir = File.join(Gitlab.config.backup.path, 'builds')
+ super('builds', Settings.gitlab_ci.builds_path)
end
- # Copy builds from builds directory to backup/builds
- def dump
- FileUtils.rm_rf(backup_builds_dir)
- # Ensure the parent dir of backup_builds_dir exists
- FileUtils.mkdir_p(Gitlab.config.backup.path)
- # Fail if somebody raced to create backup_builds_dir before us
- FileUtils.mkdir(backup_builds_dir, mode: 0700)
- FileUtils.cp_r(app_builds_dir, backup_dir)
- end
-
- def restore
- backup_existing_builds_dir
-
- FileUtils.cp_r(backup_builds_dir, app_builds_dir)
- 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
+ def create_files_dir
+ Dir.mkdir(app_files_dir, 0700)
end
end
end
diff --git a/lib/backup/database.rb b/lib/backup/database.rb
index 959ac4b786..67b2a64bd1 100644
--- a/lib/backup/database.rb
+++ b/lib/backup/database.rb
@@ -2,26 +2,26 @@ require 'yaml'
module Backup
class Database
- attr_reader :config, :db_dir
+ attr_reader :config, :db_file_name
def initialize
@config = YAML.load_file(File.join(Rails.root,'config','database.yml'))[Rails.env]
- @db_dir = File.join(Gitlab.config.backup.path, 'db')
+ @db_file_name = File.join(Gitlab.config.backup.path, 'db', 'database.sql.gz')
end
def dump
- FileUtils.rm_rf(@db_dir)
- # Ensure the parent dir of @db_dir exists
- FileUtils.mkdir_p(Gitlab.config.backup.path)
- # Fail if somebody raced to create @db_dir before us
- FileUtils.mkdir(@db_dir, mode: 0700)
+ FileUtils.mkdir_p(File.dirname(db_file_name))
+ FileUtils.rm_f(db_file_name)
+ compress_rd, compress_wr = IO.pipe
+ compress_pid = spawn(*%W(gzip -1 -c), in: compress_rd, out: [db_file_name, 'w', 0600])
+ compress_rd.close
- success = case config["adapter"]
+ dump_pid = case config["adapter"]
when /^mysql/ then
$progress.print "Dumping 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"]
- system('mysqldump', *mysql_args, config['database'], out: db_file_name)
+ spawn('mysqldump', *mysql_args, config['database'], out: compress_wr)
when "postgresql" then
$progress.print "Dumping PostgreSQL database #{config['database']} ... "
pg_env
@@ -30,48 +30,42 @@ module Backup
pgsql_args << "-n"
pgsql_args << Gitlab.config.backup.pg_schema
end
- system('pg_dump', *pgsql_args, config['database'], out: db_file_name)
+ spawn('pg_dump', *pgsql_args, config['database'], out: compress_wr)
end
+ compress_wr.close
+
+ success = [compress_pid, dump_pid].all? { |pid| Process.waitpid(pid); $?.success? }
+
report_success(success)
abort 'Backup failed' unless success
-
- $progress.print 'Compressing database ... '
- success = system('gzip', db_file_name)
- report_success(success)
- abort 'Backup failed: compress error' unless success
end
def restore
- $progress.print 'Decompressing database ... '
- success = system('gzip', '-d', db_file_name_gz)
- report_success(success)
- abort 'Restore failed: decompress error' unless success
+ decompress_rd, decompress_wr = IO.pipe
+ decompress_pid = spawn(*%W(gzip -cd), out: decompress_wr, in: db_file_name)
+ decompress_wr.close
- success = case config["adapter"]
+ 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"]
- system('mysql', *mysql_args, config['database'], in: db_file_name)
+ spawn('mysql', *mysql_args, config['database'], in: decompress_rd)
when "postgresql" then
$progress.print "Restoring PostgreSQL database #{config['database']} ... "
pg_env
- system('psql', config['database'], '-f', db_file_name)
+ spawn('psql', config['database'], in: decompress_rd)
end
+ decompress_rd.close
+
+ success = [decompress_pid, restore_pid].all? { |pid| Process.waitpid(pid); $?.success? }
+
report_success(success)
abort 'Restore failed' unless success
end
protected
- def db_file_name
- File.join(db_dir, 'database.sql')
- end
-
- def db_file_name_gz
- File.join(db_dir, 'database.sql.gz')
- end
-
def mysql_args
args = {
'host' => '--host',
diff --git a/lib/backup/files.rb b/lib/backup/files.rb
new file mode 100644
index 0000000000..654b4d1c89
--- /dev/null
+++ b/lib/backup/files.rb
@@ -0,0 +1,40 @@
+require 'open3'
+
+module Backup
+ class Files
+ attr_reader :name, :app_files_dir, :backup_tarball, :files_parent_dir
+
+ def initialize(name, app_files_dir)
+ @name = name
+ @app_files_dir = File.realpath(app_files_dir)
+ @files_parent_dir = File.realpath(File.join(@app_files_dir, '..'))
+ @backup_tarball = File.join(Gitlab.config.backup.path, name + '.tar.gz')
+ end
+
+ # Copy files from public/files to backup/files
+ def dump
+ FileUtils.mkdir_p(Gitlab.config.backup.path)
+ FileUtils.rm_f(backup_tarball)
+ run_pipeline!([%W(tar -C #{app_files_dir} -cf - .), %W(gzip -c -1)], out: [backup_tarball, 'w', 0600])
+ end
+
+ def restore
+ backup_existing_files_dir
+ create_files_dir
+
+ run_pipeline!([%W(gzip -cd), %W(tar -C #{app_files_dir} -xf -)], in: backup_tarball)
+ end
+
+ def backup_existing_files_dir
+ timestamped_files_path = File.join(files_parent_dir, "#{name}.#{Time.now.to_i}")
+ if File.exists?(app_files_dir)
+ FileUtils.mv(app_files_dir, File.expand_path(timestamped_files_path))
+ end
+ end
+
+ def run_pipeline!(cmd_list, options={})
+ status_list = Open3.pipeline(*cmd_list, options)
+ abort 'Backup failed' unless status_list.compact.all?(&:success?)
+ end
+ end
+end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index 5c42f25f4a..f011fd03de 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -150,11 +150,11 @@ module Backup
private
def backup_contents
- folders_to_backup + ["backup_information.yml"]
+ folders_to_backup + ["uploads.tar.gz", "builds.tar.gz", "backup_information.yml"]
end
def folders_to_backup
- folders = %w{repositories db uploads builds}
+ folders = %w{repositories db}
if ENV["SKIP"]
return folders.reject{ |folder| ENV["SKIP"].include?(folder) }
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index 4d70f7883d..a82a7e1f7b 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -35,7 +35,7 @@ module Backup
if wiki.repository.empty?
$progress.puts " [SKIPPED]".cyan
else
- cmd = %W(git --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all)
+ cmd = %W(#{Gitlab.config.git.bin_path} --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all)
output, status = Gitlab::Popen.popen(cmd)
if status.zero?
$progress.puts " [DONE]".green
@@ -67,7 +67,7 @@ module Backup
FileUtils.mkdir_p(path_to_repo(project))
cmd = %W(tar -xf #{path_to_bundle(project)} -C #{path_to_repo(project)})
else
- cmd = %W(git init --bare #{path_to_repo(project)})
+ cmd = %W(#{Gitlab.config.git.bin_path} init --bare #{path_to_repo(project)})
end
if system(*cmd, silent)
@@ -87,7 +87,7 @@ module Backup
# that was initialized with ProjectWiki.new() and then
# try to restore with 'git clone --bare'.
FileUtils.rm_rf(path_to_repo(wiki))
- cmd = %W(git clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)})
+ cmd = %W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)})
if system(*cmd, silent)
$progress.puts " [DONE]".green
diff --git a/lib/backup/uploads.rb b/lib/backup/uploads.rb
index 1f9626644e..9261f77f3c 100644
--- a/lib/backup/uploads.rb
+++ b/lib/backup/uploads.rb
@@ -1,34 +1,14 @@
+require 'backup/files'
+
module Backup
- class Uploads
- attr_reader :app_uploads_dir, :backup_uploads_dir, :backup_dir
+ class Uploads < Files
def initialize
- @app_uploads_dir = File.realpath(Rails.root.join('public', 'uploads'))
- @backup_dir = Gitlab.config.backup.path
- @backup_uploads_dir = File.join(Gitlab.config.backup.path, 'uploads')
+ super('uploads', Rails.root.join('public/uploads'))
end
- # Copy uploads from public/uploads to backup/uploads
- def dump
- FileUtils.rm_rf(backup_uploads_dir)
- # Ensure the parent dir of backup_uploads_dir exists
- FileUtils.mkdir_p(Gitlab.config.backup.path)
- # Fail if somebody raced to create backup_uploads_dir before us
- FileUtils.mkdir(backup_uploads_dir, mode: 0700)
- FileUtils.cp_r(app_uploads_dir, backup_dir)
- end
-
- def restore
- backup_existing_uploads_dir
-
- FileUtils.cp_r(backup_uploads_dir, app_uploads_dir)
- end
-
- def backup_existing_uploads_dir
- timestamped_uploads_path = File.join(app_uploads_dir, '..', "uploads.#{Time.now.to_i}")
- if File.exists?(app_uploads_dir)
- FileUtils.mv(app_uploads_dir, File.expand_path(timestamped_uploads_path))
- end
+ def create_files_dir
+ Dir.mkdir(app_files_dir)
end
end
end
diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb
index e602cda81d..7e4986b6af 100644
--- a/lib/ci/api/helpers.rb
+++ b/lib/ci/api/helpers.rb
@@ -16,7 +16,9 @@ module Ci
end
def update_runner_last_contact
- if current_runner.contacted_at.nil? || Time.now - current_runner.contacted_at >= UPDATE_RUNNER_EVERY
+ # Use a random threshold to prevent beating DB updates
+ contacted_at_max_age = UPDATE_RUNNER_EVERY + Random.rand(UPDATE_RUNNER_EVERY)
+ if current_runner.contacted_at.nil? || Time.now - current_runner.contacted_at >= contacted_at_max_age
current_runner.update_attributes(contacted_at: Time.now)
end
end
diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb
index efcd2faffc..0f57a4f53a 100644
--- a/lib/ci/gitlab_ci_yaml_processor.rb
+++ b/lib/ci/gitlab_ci_yaml_processor.rb
@@ -7,10 +7,11 @@ module Ci
ALLOWED_YAML_KEYS = [:before_script, :image, :services, :types, :stages, :variables]
ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when]
- attr_reader :before_script, :image, :services, :variables
+ attr_reader :before_script, :image, :services, :variables, :path
- def initialize(config)
+ def initialize(config, path = nil)
@config = YAML.load(config)
+ @path = path
unless @config.is_a? Hash
raise ValidationError, "YAML should be a hash"
@@ -63,26 +64,6 @@ module Ci
end
end
- def process?(only_params, except_params, ref, tag)
- return true if only_params.nil? && except_params.nil?
-
- if only_params
- return true if tag && only_params.include?("tags")
- return true if !tag && only_params.include?("branches")
-
- only_params.find do |pattern|
- match_ref?(pattern, ref)
- end
- else
- return false if tag && except_params.include?("tags")
- return false if !tag && except_params.include?("branches")
-
- except_params.each do |pattern|
- return false if match_ref?(pattern, ref)
- end
- end
- end
-
def build_job(name, job)
{
stage_idx: stages.index(job[:stage]),
@@ -101,14 +82,6 @@ module Ci
}
end
- def match_ref?(pattern, ref)
- if pattern.first == "/" && pattern.last == "/"
- Regexp.new(pattern[1...-1]) =~ ref
- else
- pattern == ref
- end
- end
-
def normalize_script(script)
if script.is_a? Array
script.join("\n")
@@ -208,5 +181,36 @@ module Ci
def validate_string(value)
value.is_a?(String) || value.is_a?(Symbol)
end
+
+ def process?(only_params, except_params, ref, tag)
+ if only_params.present?
+ return false unless matching?(only_params, ref, tag)
+ end
+
+ if except_params.present?
+ return false if matching?(except_params, ref, tag)
+ end
+
+ true
+ end
+
+ def matching?(patterns, ref, tag)
+ patterns.any? do |pattern|
+ match_ref?(pattern, ref, tag)
+ end
+ end
+
+ def match_ref?(pattern, ref, tag)
+ pattern, path = pattern.split('@', 2)
+ return false if path && path != self.path
+ return true if tag && pattern == 'tags'
+ return true if !tag && pattern == 'branches'
+
+ if pattern.first == "/" && pattern.last == "/"
+ Regexp.new(pattern[1...-1]) =~ ref
+ else
+ pattern == ref
+ end
+ end
end
end
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 2b8aff451d..5b52a1e75c 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -34,7 +34,7 @@ module Grack
auth!
if project && authorized_request?
- # Tell gitlab-git-http-server the request is OK, and what the GL_ID is
+ # Tell gitlab-workhorse the request is OK, and what the GL_ID is
render_grack_auth_ok
elsif @user.nil? && !@ci
unauthorized
@@ -244,12 +244,19 @@ module Grack
end
def render_grack_auth_ok
+ repo_path =
+ if @request.path_info =~ /^([\w\.\/-]+)\.wiki\.git/
+ ProjectWiki.new(project).repository.path_to_repo
+ else
+ project.repository.path_to_repo
+ end
+
[
200,
{ "Content-Type" => "application/json" },
[JSON.dump({
'GL_ID' => Gitlab::ShellEnv.gl_id(@user),
- 'RepoPath' => project.repository.path_to_repo,
+ 'RepoPath' => repo_path,
})]
]
end
diff --git a/lib/gitlab/force_push_check.rb b/lib/gitlab/force_push_check.rb
index fdb6a35c78..93c6a5bb7f 100644
--- a/lib/gitlab/force_push_check.rb
+++ b/lib/gitlab/force_push_check.rb
@@ -7,7 +7,7 @@ module Gitlab
if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev)
false
else
- missed_refs, _ = Gitlab::Popen.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
+ missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev}))
missed_refs.split("\n").size > 0
end
end
diff --git a/lib/gitlab/git_ref_validator.rb b/lib/gitlab/git_ref_validator.rb
index 39d17def93..4d83d8e72a 100644
--- a/lib/gitlab/git_ref_validator.rb
+++ b/lib/gitlab/git_ref_validator.rb
@@ -6,7 +6,7 @@ module Gitlab
# Returns true for a valid reference name, false otherwise
def validate(ref_name)
Gitlab::Utils.system_silent(
- %W(git check-ref-format refs/#{ref_name}))
+ %W(#{Gitlab.config.git.bin_path} check-ref-format refs/#{ref_name}))
end
end
end
diff --git a/lib/gitlab/markdown/sanitization_filter.rb b/lib/gitlab/markdown/sanitization_filter.rb
index e368de7d84..ffb9dc33b6 100644
--- a/lib/gitlab/markdown/sanitization_filter.rb
+++ b/lib/gitlab/markdown/sanitization_filter.rb
@@ -48,6 +48,12 @@ module Gitlab
# Allow span elements
whitelist[:elements].push('span')
+ # Allow any protocol in `a` elements...
+ whitelist[:protocols].delete('a')
+
+ # ...but then remove links with the `javascript` protocol
+ whitelist[:transformers].push(remove_javascript_links)
+
# Remove `rel` attribute from `a` elements
whitelist[:transformers].push(remove_rel)
@@ -57,6 +63,19 @@ module Gitlab
whitelist
end
+ def remove_javascript_links
+ lambda do |env|
+ node = env[:node]
+
+ return unless node.name == 'a'
+ return unless node.has_attribute?('href')
+
+ if node['href'].start_with?('javascript', ':javascript')
+ node.remove_attribute('href')
+ end
+ end
+ end
+
def remove_rel
lambda do |env|
if env[:node_name] == 'a'
diff --git a/lib/gitlab/o_auth/provider.rb b/lib/gitlab/o_auth/provider.rb
index 90c3fe8da3..9ad7a38d50 100644
--- a/lib/gitlab/o_auth/provider.rb
+++ b/lib/gitlab/o_auth/provider.rb
@@ -1,6 +1,12 @@
module Gitlab
module OAuth
class Provider
+ LABELS = {
+ "github" => "GitHub",
+ "gitlab" => "GitLab.com",
+ "google_oauth2" => "Google"
+ }.freeze
+
def self.providers
Devise.omniauth_providers
end
@@ -23,8 +29,9 @@ module Gitlab
end
def self.label_for(name)
+ name = name.to_s
config = config_for(name)
- (config && config['label']) || name.to_s.titleize
+ (config && config['label']) || LABELS[name] || name.titleize
end
end
end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index 0dab7bcfa4..70de6a74e7 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -9,7 +9,7 @@ module Gitlab
else
nil
end
- @query = Shellwords.shellescape(query) if query.present?
+ @query = query
end
def objects(scope, page = nil)
@@ -20,6 +20,8 @@ module Gitlab
Kaminari.paginate_array(blobs).page(page).per(per_page)
when 'wiki_blobs'
Kaminari.paginate_array(wiki_blobs).page(page).per(per_page)
+ when 'commits'
+ Kaminari.paginate_array(commits).page(page).per(per_page)
else
super
end
@@ -27,7 +29,7 @@ module Gitlab
def total_count
@total_count ||= issues_count + merge_requests_count + blobs_count +
- notes_count + wiki_blobs_count
+ notes_count + wiki_blobs_count + commits_count
end
def blobs_count
@@ -42,6 +44,10 @@ module Gitlab
@wiki_blobs_count ||= wiki_blobs.count
end
+ def commits_count
+ @commits_count ||= commits.count
+ end
+
private
def blobs
@@ -70,6 +76,14 @@ module Gitlab
Note.where(project_id: limit_project_ids).user.search(query).order('updated_at DESC')
end
+ def commits
+ if project.empty_repo? || query.blank?
+ []
+ else
+ project.repository.find_commits_by_message(query).compact
+ end
+ end
+
def limit_project_ids
[project.id]
end
diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb
index d010ade704..fa068d5076 100644
--- a/lib/gitlab/push_data_builder.rb
+++ b/lib/gitlab/push_data_builder.rb
@@ -18,7 +18,10 @@ module Gitlab
# homepage: String,
# },
# commits: Array,
- # total_commits_count: Fixnum
+ # total_commits_count: Fixnum,
+ # added: ["CHANGELOG"],
+ # modified: [],
+ # removed: ["tmp/file.txt"]
# }
#
def build(project, user, oldrev, newrev, ref, commits = [], message = nil)
@@ -33,6 +36,8 @@ module Gitlab
commit_attrs = commits_limited.map(&:hook_attrs)
type = Gitlab::Git.tag_ref?(ref) ? "tag_push" : "push"
+
+ repo_changes = repo_changes(project, newrev, oldrev)
# Hash to be passed as post_receive_data
data = {
object_kind: type,
@@ -55,7 +60,10 @@ module Gitlab
visibility_level: project.visibility_level
},
commits: commit_attrs,
- total_commits_count: commits_count
+ total_commits_count: commits_count,
+ added: repo_changes[:added],
+ modified: repo_changes[:modified],
+ removed: repo_changes[:removed]
}
data
@@ -86,6 +94,27 @@ module Gitlab
newrev
end
end
+
+ def repo_changes(project, newrev, oldrev)
+ changes = { added: [], modified: [], removed: [] }
+ compare_result = CompareService.new.
+ execute(project, newrev, project, oldrev)
+
+ if compare_result
+ compare_result.diffs.each do |diff|
+ case true
+ when diff.deleted_file
+ changes[:removed] << diff.old_path
+ when diff.renamed_file, diff.new_file
+ changes[:added] << diff.new_path
+ else
+ changes[:modified] << diff.new_path
+ end
+ end
+ end
+
+ changes
+ end
end
end
end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 9f1adc860d..53ab2686b4 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -51,6 +51,23 @@ module Gitlab
"can contain only letters, digits, '_', '-' and '.'. "
end
+ def file_path_regex
+ @file_path_regex ||= /\A[a-zA-Z0-9_\-\.\/]*\z/.freeze
+ end
+
+ def file_path_regex_message
+ "can contain only letters, digits, '_', '-' and '.'. Separate directories with a '/'. "
+ end
+
+
+ def directory_traversal_regex
+ @directory_traversal_regex ||= /\.{2}/.freeze
+ end
+
+ def directory_traversal_regex_message
+ "cannot include directory traversal. "
+ end
+
def archive_formats_regex
# |zip|tar| tar.gz | tar.bz2 |
diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb
index e152a330d2..d329e3fdf7 100644
--- a/lib/gitlab/upgrader.rb
+++ b/lib/gitlab/upgrader.rb
@@ -50,15 +50,15 @@ module Gitlab
end
def fetch_git_tags
- remote_tags, _ = Gitlab::Popen.popen(%W(git ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ee.git))
+ remote_tags, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ee.git))
remote_tags.split("\n").grep(/tags\/v#{current_version.major}/)
end
def update_commands
{
- "Stash changed files" => %W(git stash),
- "Get latest code" => %W(git fetch),
- "Switch to new version" => %W(git checkout v#{latest_version}-ee),
+ "Stash changed files" => %W(#{Gitlab.config.git.bin_path} stash),
+ "Get latest code" => %W(#{Gitlab.config.git.bin_path} fetch),
+ "Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}-ee),
"Install gems" => %W(bundle),
"Migrate DB" => %W(bundle exec rake db:migrate),
"Recompile assets" => %W(bundle exec rake assets:clean assets:precompile),
diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab
index a80e7e7743..f0a6c2b30e 100755
--- a/lib/support/init.d/gitlab
+++ b/lib/support/init.d/gitlab
@@ -37,10 +37,9 @@ web_server_pid_path="$pid_path/unicorn.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
mail_room_enabled=false
mail_room_pid_path="$pid_path/mail_room.pid"
-gitlab_git_http_server_pid_path="$pid_path/gitlab-git-http-server.pid"
-gitlab_git_http_server_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-git-http-server.socket -authBackend http://127.0.0.1:8080"
-gitlab_git_http_server_repo_root='/home/git/repositories'
-gitlab_git_http_server_log="$app_root/log/gitlab-git-http-server.log"
+gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
+gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080"
+gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
shell_path="/bin/bash"
# Read configuration variable file if it is present
@@ -76,8 +75,8 @@ check_pids(){
else
spid=0
fi
- if [ -f "$gitlab_git_http_server_pid_path" ]; then
- hpid=$(cat "$gitlab_git_http_server_pid_path")
+ if [ -f "$gitlab_workhorse_pid_path" ]; then
+ hpid=$(cat "$gitlab_workhorse_pid_path")
else
hpid=0
fi
@@ -94,7 +93,7 @@ check_pids(){
wait_for_pids(){
# We are sleeping a bit here mostly because sidekiq is slow at writing it's pid
i=0;
- while [ ! -f $web_server_pid_path ] || [ ! -f $sidekiq_pid_path ] || [ ! -f $gitlab_git_http_server_pid_path ] || { [ "$mail_room_enabled" = true ] && [ ! -f $mail_room_pid_path ]; }; do
+ while [ ! -f $web_server_pid_path ] || [ ! -f $sidekiq_pid_path ] || [ ! -f $gitlab_workhorse_pid_path ] || { [ "$mail_room_enabled" = true ] && [ ! -f $mail_room_pid_path ]; }; do
sleep 0.1;
i=$((i+1))
if [ $((i%10)) = 0 ]; then
@@ -131,9 +130,9 @@ check_status(){
fi
if [ $hpid -ne 0 ]; then
kill -0 "$hpid" 2>/dev/null
- gitlab_git_http_server_status="$?"
+ gitlab_workhorse_status="$?"
else
- gitlab_git_http_server_status="-1"
+ gitlab_workhorse_status="-1"
fi
if [ "$mail_room_enabled" = true ]; then
if [ $mpid -ne 0 ]; then
@@ -143,7 +142,7 @@ check_status(){
mail_room_status="-1"
fi
fi
- if [ $web_status = 0 ] && [ $sidekiq_status = 0 ] && [ $gitlab_git_http_server_status = 0 ] && { [ "$mail_room_enabled" != true ] || [ $mail_room_status = 0 ]; }; then
+ if [ $web_status = 0 ] && [ $sidekiq_status = 0 ] && [ $gitlab_workhorse_status = 0 ] && { [ "$mail_room_enabled" != true ] || [ $mail_room_status = 0 ]; }; then
gitlab_status=0
else
# http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
@@ -171,9 +170,9 @@ check_stale_pids(){
exit 1
fi
fi
- if [ "$hpid" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ]; then
- echo "Removing stale gitlab-git-http-server pid. This is most likely caused by gitlab-git-http-server crashing the last time it ran."
- if ! rm "$gitlab_git_http_server_pid_path"; then
+ if [ "$hpid" != "0" ] && [ "$gitlab_workhorse_status" != "0" ]; then
+ echo "Removing stale gitlab-workhorse pid. This is most likely caused by gitlab-workhorse crashing the last time it ran."
+ if ! rm "$gitlab_workhorse_pid_path"; then
echo "Unable to remove stale pid, exiting"
exit 1
fi
@@ -190,7 +189,7 @@ check_stale_pids(){
## If no parts of the service is running, bail out.
exit_if_not_running(){
check_stale_pids
- if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_workhorse_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
echo "GitLab is not running."
exit
fi
@@ -206,8 +205,8 @@ start_gitlab() {
if [ "$sidekiq_status" != "0" ]; then
echo "Starting GitLab Sidekiq"
fi
- if [ "$gitlab_git_http_server_status" != "0" ]; then
- echo "Starting gitlab-git-http-server"
+ if [ "$gitlab_workhorse_status" != "0" ]; then
+ echo "Starting gitlab-workhorse"
fi
if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" != "0" ]; then
echo "Starting GitLab MailRoom"
@@ -230,15 +229,14 @@ start_gitlab() {
RAILS_ENV=$RAILS_ENV bin/background_jobs start &
fi
- if [ "$gitlab_git_http_server_status" = "0" ]; then
- echo "The gitlab-git-http-server is already running with pid $spid, not restarting"
+ if [ "$gitlab_workhorse_status" = "0" ]; then
+ echo "The gitlab-workhorse is already running with pid $spid, not restarting"
else
- # No need to remove a socket, gitlab-git-http-server does this itself
- $app_root/bin/daemon_with_pidfile $gitlab_git_http_server_pid_path \
- $app_root/../gitlab-git-http-server/gitlab-git-http-server \
- $gitlab_git_http_server_options \
- $gitlab_git_http_server_repo_root \
- >> $gitlab_git_http_server_log 2>&1 &
+ # No need to remove a socket, gitlab-workhorse does this itself
+ $app_root/bin/daemon_with_pidfile $gitlab_workhorse_pid_path \
+ $app_root/../gitlab-workhorse/gitlab-workhorse \
+ $gitlab_workhorse_options \
+ >> $gitlab_workhorse_log 2>&1 &
fi
if [ "$mail_room_enabled" = true ]; then
@@ -268,9 +266,9 @@ stop_gitlab() {
echo "Shutting down GitLab Sidekiq"
RAILS_ENV=$RAILS_ENV bin/background_jobs stop
fi
- if [ "$gitlab_git_http_server_status" = "0" ]; then
- echo "Shutting down gitlab-git-http-server"
- kill -- $(cat $gitlab_git_http_server_pid_path)
+ if [ "$gitlab_workhorse_status" = "0" ]; then
+ echo "Shutting down gitlab-workhorse"
+ kill -- $(cat $gitlab_workhorse_pid_path)
fi
if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; then
echo "Shutting down GitLab MailRoom"
@@ -278,11 +276,11 @@ stop_gitlab() {
fi
# If something needs to be stopped, lets wait for it to stop. Never use SIGKILL in a script.
- while [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_git_http_server_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; do
+ while [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_workhorse_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; do
sleep 1
check_status
printf "."
- if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_workhorse_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
printf "\n"
break
fi
@@ -292,7 +290,7 @@ stop_gitlab() {
# Cleaning up unused pids
rm "$web_server_pid_path" 2>/dev/null
# rm "$sidekiq_pid_path" 2>/dev/null # Sidekiq seems to be cleaning up it's own pid.
- rm -f "$gitlab_git_http_server_pid_path"
+ rm -f "$gitlab_workhorse_pid_path"
if [ "$mail_room_enabled" = true ]; then
rm "$mail_room_pid_path" 2>/dev/null
fi
@@ -303,7 +301,7 @@ stop_gitlab() {
## Prints the status of GitLab and it's components.
print_status() {
check_status
- if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
+ if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_workhorse_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
echo "GitLab is not running."
return
fi
@@ -317,10 +315,10 @@ print_status() {
else
printf "The GitLab Sidekiq job dispatcher is \033[31mnot running\033[0m.\n"
fi
- if [ "$gitlab_git_http_server_status" = "0" ]; then
- echo "The gitlab-git-http-server with pid $hpid is running."
+ if [ "$gitlab_workhorse_status" = "0" ]; then
+ echo "The gitlab-workhorse with pid $hpid is running."
else
- printf "The gitlab-git-http-server is \033[31mnot running\033[0m.\n"
+ printf "The gitlab-workhorse is \033[31mnot running\033[0m.\n"
fi
if [ "$mail_room_enabled" = true ]; then
if [ "$mail_room_status" = "0" ]; then
@@ -360,7 +358,7 @@ reload_gitlab(){
## Restarts Sidekiq and Unicorn.
restart_gitlab(){
check_status
- if [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_git_http_server" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; then
+ if [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_workhorse" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; then
stop_gitlab
fi
start_gitlab
diff --git a/lib/support/init.d/gitlab.default.example b/lib/support/init.d/gitlab.default.example
index aab5acaa72..79ae8e0ae5 100755
--- a/lib/support/init.d/gitlab.default.example
+++ b/lib/support/init.d/gitlab.default.example
@@ -30,15 +30,14 @@ web_server_pid_path="$pid_path/unicorn.pid"
# The default is "$pid_path/sidekiq.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid"
-gitlab_git_http_server_pid_path="$pid_path/gitlab-git-http-server.pid"
-# The -listenXxx settings determine where gitlab-git-http-server
+gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
+# The -listenXxx settings determine where gitlab-workhorse
# listens for connections from NGINX. To listen on localhost:8181, write
# '-listenNetwork tcp -listenAddr localhost:8181'.
-# The -authBackend setting tells gitlab-git-http-server where it can reach
+# The -authBackend setting tells gitlab-workhorse where it can reach
# Unicorn.
-gitlab_git_http_server_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-git-http-server.socket -authBackend http://127.0.0.1:8080"
-gitlab_git_http_server_repo_root="/home/git/repositories"
-gitlab_git_http_server_log="$app_root/log/gitlab-git-http-server.log"
+gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080"
+gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
# mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled.
# This is required for the Reply by email feature.
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 1e55c5a048..e767027dc2 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -38,8 +38,8 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
-upstream gitlab-git-http-server {
- server unix:/home/git/gitlab/tmp/sockets/gitlab-git-http-server.socket fail_timeout=0;
+upstream gitlab-workhorse {
+ server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
## Normal HTTP host
@@ -114,24 +114,24 @@ server {
}
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;
+ # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
+ error_page 418 = @gitlab-workhorse;
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;
+ # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
+ error_page 418 = @gitlab-workhorse;
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;
+ # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
+ error_page 418 = @gitlab-workhorse;
return 418;
}
- location @gitlab-git-http-server {
+ location @gitlab-workhorse {
## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
# gzip off;
@@ -147,7 +147,7 @@ server {
# The following settings only work with NGINX 1.7.11 or newer
#
- # # Pass chunked request bodies to gitlab-git-http-server as-is
+ # # Pass chunked request bodies to gitlab-workhorse as-is
# proxy_request_buffering off;
# proxy_http_version 1.1;
@@ -156,7 +156,7 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
- proxy_pass http://gitlab-git-http-server;
+ proxy_pass http://gitlab-workhorse;
}
## Enable gzip compression as per rails guide:
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 08641bbcc1..4d31e31f8d 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -42,8 +42,8 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
-upstream gitlab-git-http-server {
- server unix:/home/git/gitlab/tmp/sockets/gitlab-git-http-server.socket fail_timeout=0;
+upstream gitlab-workhorse {
+ server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
## Redirects all HTTP traffic to the HTTPS host
@@ -161,24 +161,24 @@ server {
}
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;
+ # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
+ error_page 418 = @gitlab-workhorse;
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;
+ # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
+ error_page 418 = @gitlab-workhorse;
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;
+ # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
+ error_page 418 = @gitlab-workhorse;
return 418;
}
- location @gitlab-git-http-server {
+ location @gitlab-workhorse {
## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack.
gzip off;
@@ -194,7 +194,7 @@ server {
# The following settings only work with NGINX 1.7.11 or newer
#
- # # Pass chunked request bodies to gitlab-git-http-server as-is
+ # # Pass chunked request bodies to gitlab-workhorse as-is
# proxy_request_buffering off;
# proxy_http_version 1.1;
@@ -203,7 +203,7 @@ server {
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
- proxy_pass http://gitlab-git-http-server;
+ proxy_pass http://gitlab-workhorse;
}
## Enable gzip compression as per rails guide:
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 2e73f792a9..a25fac62cf 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -824,7 +824,7 @@ namespace :gitlab do
repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
repo_dirs.each do |dir|
puts "\nChecking repo at #{dir}"
- system(*%w(git fsck), chdir: dir)
+ system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: dir)
end
end
end
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index 3c0cc763d1..dd61632e55 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -17,7 +17,7 @@ namespace :gitlab do
# Clone if needed
unless File.directory?(target_dir)
- system(*%W(git clone -- #{args.repo} #{target_dir}))
+ system(*%W(#{Gitlab.config.git.bin_path} clone -- #{args.repo} #{target_dir}))
end
# Make sure we're on the right tag
@@ -27,7 +27,7 @@ namespace :gitlab do
reseted = reset_to_commit(args)
unless reseted
- system(*%W(git fetch origin))
+ system(*%W(#{Gitlab.config.git.bin_path} fetch origin))
reset_to_commit(args)
end
@@ -128,14 +128,14 @@ namespace :gitlab do
end
def reset_to_commit(args)
- tag, status = Gitlab::Popen.popen(%W(git describe -- #{args.tag}))
+ tag, status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} describe -- #{args.tag}))
unless status.zero?
- tag, status = Gitlab::Popen.popen(%W(git describe -- origin/#{args.tag}))
+ tag, status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} describe -- origin/#{args.tag}))
end
tag = tag.strip
- system(*%W(git reset --hard #{tag}))
+ system(*%W(#{Gitlab.config.git.bin_path} reset --hard #{tag}))
end
end
diff --git a/lib/tasks/spinach.rake b/lib/tasks/spinach.rake
index c8881be095..d5a96fd38f 100644
--- a/lib/tasks/spinach.rake
+++ b/lib/tasks/spinach.rake
@@ -5,7 +5,7 @@ namespace :spinach do
task :project do
cmds = [
%W(rake gitlab:setup),
- %W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets),
+ %W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets,~@commits),
]
run_commands(cmds)
end
@@ -14,7 +14,7 @@ namespace :spinach do
task :other do
cmds = [
%W(rake gitlab:setup),
- %W(spinach --tags @admin,@dashboard,@profile,@public,@snippets),
+ %W(spinach --tags @admin,@dashboard,@profile,@public,@snippets,@commits),
]
run_commands(cmds)
end
@@ -33,4 +33,4 @@ def run_commands(cmds)
cmds.each do |cmd|
system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd) or raise("#{cmd} failed!")
end
-end
+end
\ No newline at end of file
diff --git a/shared/.gitkeep b/shared/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/spec/benchmarks/models/user_spec.rb b/spec/benchmarks/models/user_spec.rb
index cc5c390419..1be7a8d3ed 100644
--- a/spec/benchmarks/models/user_spec.rb
+++ b/spec/benchmarks/models/user_spec.rb
@@ -1,6 +1,16 @@
require 'spec_helper'
describe User, benchmark: true do
+ describe '.all' do
+ before do
+ 10.times { create(:user) }
+ end
+
+ benchmark_subject { User.all.to_a }
+
+ it { is_expected.to iterate_per_second(500) }
+ end
+
describe '.by_login' do
before do
%w{Alice Bob Eve}.each do |name|
@@ -39,4 +49,30 @@ describe User, benchmark: true do
it { is_expected.to iterate_per_second(iterations) }
end
end
+
+ describe '.find_by_any_email' do
+ let(:user) { create(:user) }
+
+ describe 'using a user with only a single Email address' do
+ let(:email) { user.email }
+
+ benchmark_subject { User.find_by_any_email(email) }
+
+ it { is_expected.to iterate_per_second(1000) }
+ end
+
+ describe 'using a user with multiple Email addresses' do
+ let(:email) { user.emails.first.email }
+
+ benchmark_subject { User.find_by_any_email(email) }
+
+ before do
+ 10.times do
+ user.emails.create(email: FFaker::Internet.email)
+ end
+ end
+
+ it { is_expected.to iterate_per_second(1000) }
+ end
+ end
end
diff --git a/spec/benchmarks/services/projects/create_service_spec.rb b/spec/benchmarks/services/projects/create_service_spec.rb
new file mode 100644
index 0000000000..25ed48c34f
--- /dev/null
+++ b/spec/benchmarks/services/projects/create_service_spec.rb
@@ -0,0 +1,28 @@
+require 'spec_helper'
+
+describe Projects::CreateService, benchmark: true do
+ describe '#execute' do
+ let(:user) { create(:user, :admin) }
+
+ let(:group) do
+ group = create(:group)
+
+ create(:group_member, group: group, user: user)
+
+ group
+ end
+
+ benchmark_subject do
+ name = SecureRandom.hex
+ service = described_class.new(user,
+ name: name,
+ path: name,
+ namespace_id: group.id,
+ visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+
+ service.execute
+ end
+
+ it { is_expected.to iterate_per_second(0.5) }
+ end
+end
diff --git a/spec/features/ci/events_spec.rb b/spec/features/ci/events_spec.rb
deleted file mode 100644
index 5b9fd40415..0000000000
--- a/spec/features/ci/events_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-
-describe "Events" do
- let(:user) { create(:user) }
- let(:project) { FactoryGirl.create :ci_project }
- let(:event) { FactoryGirl.create :ci_admin_event, project: project }
-
- before do
- login_as(user)
- project.gl_project.team << [user, :master]
- end
-
- describe "GET /ci/project/:id/events" do
- before do
- event
- visit ci_project_events_path(project)
- end
-
- it { expect(page).to have_content "Events" }
- it { expect(page).to have_content event.description }
- end
-end
diff --git a/spec/finders/group_finder_spec.rb b/spec/finders/group_finder_spec.rb
new file mode 100644
index 0000000000..78dc027837
--- /dev/null
+++ b/spec/finders/group_finder_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe GroupsFinder do
+ let(:user) { create :user }
+ let!(:group) { create :group }
+ let!(:public_group) { create :group, public: true }
+
+ describe :execute do
+ it 'finds public group' do
+ groups = GroupsFinder.new.execute(user)
+ expect(groups.size).to eq(1)
+ expect(groups.first).to eq(public_group)
+ end
+ end
+end
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index b327f4f911..ebe9c29d91 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -42,6 +42,11 @@ describe SearchHelper do
expect(search_autocomplete_opts(project.name).size).to eq(1)
end
+ it "includes the public group" do
+ group = create(:group, public: true)
+ expect(search_autocomplete_opts(group.name).size).to eq(1)
+ end
+
context "with a current project" do
before { @project = create(:project) }
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index abdb6b89ac..9963f76f99 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
module Ci
describe GitlabCiYamlProcessor do
-
+ let(:path) { 'path' }
+
describe "#builds_for_ref" do
let(:type) { 'test' }
@@ -12,7 +13,7 @@ module Ci
rspec: { script: "rspec" }
})
- config_processor = GitlabCiYamlProcessor.new(config)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
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({
@@ -28,78 +29,218 @@ module Ci
when: "on_success"
})
end
+
+ describe :only do
+ it "does not return builds if only has another branch" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", only: ["deploy"] }
+ })
- it "does not return builds if only has another branch" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", only: ["deploy"] }
- })
+ config_processor = GitlabCiYamlProcessor.new(config, path)
- config_processor = GitlabCiYamlProcessor.new(config)
+ expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0)
+ end
- expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0)
+ it "does not return builds if only has regexp with another branch" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", only: ["/^deploy$/"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0)
+ end
+
+ it "returns builds if only has specified this branch" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", only: ["master"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
+ end
+
+ it "returns builds if only has a list of branches including specified" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, only: ["master", "deploy"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
+ end
+
+ it "returns builds if only has a branches keyword specified" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, only: ["branches"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
+ end
+
+ it "does not return builds if only has a tags keyword" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, only: ["tags"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
+ end
+
+ it "returns builds if only has current repository path" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, only: ["branches@path"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
+ end
+
+ it "does not return builds if only has different repository path" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, only: ["branches@fork"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
+ end
+
+ it "returns build only for specified type" do
+
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: "test", only: ["master", "deploy"] },
+ staging: { script: "deploy", type: "deploy", only: ["master", "deploy"] },
+ production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] },
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, 'fork')
+
+ expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2)
+ expect(config_processor.builds_for_stage_and_ref("test", "deploy").size).to eq(1)
+ expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(1)
+ end
end
- it "does not return builds if only has regexp with another branch" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", only: ["/^deploy$/"] }
- })
+ describe :except do
+ it "returns builds if except has another branch" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", except: ["deploy"] }
+ })
- config_processor = GitlabCiYamlProcessor.new(config)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
- expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0)
+ expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
+ end
+
+ it "returns builds if except has regexp with another branch" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", except: ["/^deploy$/"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
+ end
+
+ it "does not return builds if except has specified this branch" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", except: ["master"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0)
+ end
+
+ it "does not return builds if except has a list of branches including specified" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, except: ["master", "deploy"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
+ end
+
+ it "does not return builds if except has a branches keyword specified" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, except: ["branches"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
+ end
+
+ it "returns builds if except has a tags keyword" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, except: ["tags"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
+ end
+
+ it "does not return builds if except has current repository path" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, except: ["branches@path"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
+ end
+
+ it "returns builds if except has different repository path" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: type, except: ["branches@fork"] }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, path)
+
+ expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
+ end
+
+ it "returns build except specified type" do
+ config = YAML.dump({
+ before_script: ["pwd"],
+ rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@fork"] },
+ staging: { script: "deploy", type: "deploy", except: ["master"] },
+ production: { script: "deploy", type: "deploy", except: ["master@fork"] },
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config, 'fork')
+
+ expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2)
+ expect(config_processor.builds_for_stage_and_ref("test", "test").size).to eq(0)
+ expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(0)
+ end
end
- it "returns builds if only has specified this branch" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", only: ["master"] }
- })
-
- config_processor = GitlabCiYamlProcessor.new(config)
-
- expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
- end
-
- it "does not build tags" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", except: ["tags"] }
- })
-
- config_processor = GitlabCiYamlProcessor.new(config)
-
- expect(config_processor.builds_for_stage_and_ref(type, "0-1", true).size).to eq(0)
- end
-
- it "returns builds if only has a list of branches including specified" do
- config = YAML.dump({
- before_script: ["pwd"],
- rspec: { script: "rspec", type: type, only: ["master", "deploy"] }
- })
-
- config_processor = GitlabCiYamlProcessor.new(config)
-
- expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
- end
-
- it "returns build only for specified type" do
-
- config = YAML.dump({
- before_script: ["pwd"],
- build: { script: "build", type: "build", only: ["master", "deploy"] },
- rspec: { script: "rspec", type: type, only: ["master", "deploy"] },
- staging: { script: "deploy", type: "deploy", only: ["master", "deploy"] },
- production: { script: "deploy", type: "deploy", only: ["master", "deploy"] },
- })
-
- config_processor = GitlabCiYamlProcessor.new(config)
-
- expect(config_processor.builds_for_stage_and_ref("production", "deploy").size).to eq(0)
- expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
- expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2)
- end
end
describe "Image and service handling" do
@@ -111,7 +252,7 @@ module Ci
rspec: { script: "rspec" }
})
- config_processor = GitlabCiYamlProcessor.new(config)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
@@ -139,7 +280,7 @@ module Ci
rspec: { image: "ruby:2.5", services: ["postgresql"], script: "rspec" }
})
- config_processor = GitlabCiYamlProcessor.new(config)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
@@ -172,7 +313,7 @@ module Ci
rspec: { script: "rspec" }
})
- config_processor = GitlabCiYamlProcessor.new(config)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
expect(config_processor.variables).to eq(variables)
end
end
@@ -184,7 +325,7 @@ module Ci
rspec: { script: "rspec", when: when_state }
})
- config_processor = GitlabCiYamlProcessor.new(config)
+ config_processor = GitlabCiYamlProcessor.new(config, path)
builds = config_processor.builds_for_stage_and_ref("test", "master")
expect(builds.size).to eq(1)
expect(builds.first[:when]).to eq(when_state)
@@ -200,154 +341,154 @@ module Ci
it "returns errors if tags parameter is invalid" do
config = YAML.dump({ rspec: { script: "test", tags: "mysql" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: tags parameter should be an array of strings")
end
it "returns errors if before_script parameter is invalid" do
config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings")
end
it "returns errors if image parameter is invalid" do
config = YAML.dump({ image: ["test"], rspec: { script: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
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)
+ GitlabCiYamlProcessor.new(config, path)
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)
+ GitlabCiYamlProcessor.new(config, path)
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
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: image should be a string")
end
it "returns errors if services parameter is not an array" do
config = YAML.dump({ services: "test", rspec: { script: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services should be an array of strings")
end
it "returns errors if services parameter is not an array of strings" do
config = YAML.dump({ services: [10, "test"], rspec: { script: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services should be an array of strings")
end
it "returns errors if job services parameter is not an array" do
config = YAML.dump({ rspec: { script: "test", services: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings")
end
it "returns errors if job services parameter is not an array of strings" do
config = YAML.dump({ rspec: { script: "test", services: [10, "test"] } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings")
end
it "returns errors if there are unknown parameters" do
config = YAML.dump({ extra: "bundle update" })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra")
end
it "returns errors if there are unknown parameters that are hashes, but doesn't have a script" do
config = YAML.dump({ extra: { services: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra")
end
it "returns errors if there is no any jobs defined" do
config = YAML.dump({ before_script: ["bundle update"] })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Please define at least one job")
end
it "returns errors if job allow_failure parameter is not an boolean" do
config = YAML.dump({ rspec: { script: "test", allow_failure: "string" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: allow_failure parameter should be an boolean")
end
it "returns errors if job stage is not a string" do
config = YAML.dump({ rspec: { script: "test", type: 1, allow_failure: "string" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy")
end
it "returns errors if job stage is not a pre-defined stage" do
config = YAML.dump({ rspec: { script: "test", type: "acceptance", allow_failure: "string" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy")
end
it "returns errors if job stage is not a defined stage" do
config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", type: "acceptance", allow_failure: "string" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test")
end
it "returns errors if stages is not an array" do
config = YAML.dump({ types: "test", rspec: { script: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages should be an array of strings")
end
it "returns errors if stages is not an array of strings" do
config = YAML.dump({ types: [true, "test"], rspec: { script: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages should be an array of strings")
end
it "returns errors if variables is not a map" do
config = YAML.dump({ variables: "test", rspec: { script: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings")
end
it "returns errors if variables is not a map of key-valued strings" do
config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } })
expect do
- GitlabCiYamlProcessor.new(config)
+ GitlabCiYamlProcessor.new(config, path)
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)
+ GitlabCiYamlProcessor.new(config, path)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always")
end
end
diff --git a/spec/lib/gitlab/backend/grack_auth_spec.rb b/spec/lib/gitlab/backend/grack_auth_spec.rb
index 37c527221a..dfa0e10318 100644
--- a/spec/lib/gitlab/backend/grack_auth_spec.rb
+++ b/spec/lib/gitlab/backend/grack_auth_spec.rb
@@ -50,6 +50,22 @@ describe Grack::Auth do
end
end
+ context "when the Wiki for a project exists" do
+ before do
+ @wiki = ProjectWiki.new(project)
+ env["PATH_INFO"] = "#{@wiki.repository.path_with_namespace}.git/info/refs"
+ project.update_attribute(:visibility_level, Project::PUBLIC)
+ end
+
+ it "responds with the right project" do
+ response = auth.call(env)
+ json_body = ActiveSupport::JSON.decode(response[2][0])
+
+ expect(response.first).to eq(200)
+ expect(json_body['RepoPath']).to include(@wiki.repository.path_with_namespace)
+ end
+ end
+
context "when the project exists" do
before do
env["PATH_INFO"] = project.path_with_namespace + ".git"
diff --git a/spec/lib/gitlab/markdown/sanitization_filter_spec.rb b/spec/lib/gitlab/markdown/sanitization_filter_spec.rb
index e50c82d0b3..27cd00e805 100644
--- a/spec/lib/gitlab/markdown/sanitization_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/sanitization_filter_spec.rb
@@ -44,7 +44,7 @@ module Gitlab::Markdown
instance = described_class.new('Foo')
3.times { instance.whitelist }
- expect(instance.whitelist[:transformers].size).to eq 4
+ expect(instance.whitelist[:transformers].size).to eq 5
end
it 'allows syntax highlighting' do
@@ -77,19 +77,100 @@ module Gitlab::Markdown
end
it 'removes `rel` attribute from `a` elements' do
- doc = filter(%q{Link})
+ act = %q{Link}
+ exp = %q{Link}
- expect(doc.css('a').size).to eq 1
- expect(doc.at_css('a')['href']).to eq '#'
- expect(doc.at_css('a')['rel']).to be_nil
+ expect(filter(act).to_html).to eq exp
end
- it 'removes script-like `href` attribute from `a` elements' do
- html = %q{Hi}
- doc = filter(html)
+ # Adapted from the Sanitize test suite: http://git.io/vczrM
+ protocols = {
+ 'protocol-based JS injection: simple, no spaces' => {
+ input: 'foo',
+ output: 'foo'
+ },
- expect(doc.css('a').size).to eq 1
- expect(doc.at_css('a')['href']).to be_nil
+ 'protocol-based JS injection: simple, spaces before' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: simple, spaces after' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: simple, spaces before and after' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: preceding colon' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: UTF-8 encoding' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: long UTF-8 encoding' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: long UTF-8 encoding without semicolons' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: hex encoding' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: long hex encoding' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: hex encoding without semicolons' => {
+ input: 'foo',
+ output: 'foo'
+ },
+
+ 'protocol-based JS injection: null char' => {
+ input: "foo",
+ output: ''
+ },
+
+ 'protocol-based JS injection: spaces and entities' => {
+ input: 'foo',
+ output: 'foo'
+ },
+ }
+
+ protocols.each do |name, data|
+ it "handles #{name}" do
+ doc = filter(data[:input])
+
+ expect(doc.to_html).to eq data[:output]
+ end
+ end
+
+ it 'allows non-standard anchor schemes' do
+ exp = %q{IRC}
+ act = filter(exp)
+
+ expect(act.to_html).to eq exp
+ end
+
+ it 'allows relative links' do
+ exp = %q{foo/bar.md}
+ act = filter(exp)
+
+ expect(act.to_html).to eq exp
end
end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index 32a25f08ca..19327ac8ce 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -9,7 +9,7 @@ describe Gitlab::ProjectSearchResults do
it { expect(results.project).to eq(project) }
it { expect(results.repository_ref).to be_nil }
- it { expect(results.query).to eq('hello\\ world') }
+ it { expect(results.query).to eq('hello world') }
end
describe 'initialize with ref' do
@@ -18,6 +18,6 @@ describe Gitlab::ProjectSearchResults do
it { expect(results.project).to eq(project) }
it { expect(results.repository_ref).to eq(ref) }
- it { expect(results.query).to eq('hello\\ world') }
+ it { expect(results.query).to eq('hello world') }
end
end
diff --git a/spec/lib/gitlab/push_data_builder_spec.rb b/spec/lib/gitlab/push_data_builder_spec.rb
index 1b8ba7b4d4..0271074262 100644
--- a/spec/lib/gitlab/push_data_builder_spec.rb
+++ b/spec/lib/gitlab/push_data_builder_spec.rb
@@ -17,6 +17,9 @@ describe 'Gitlab::PushDataBuilder' do
it { expect(data[:repository][:git_ssh_url]).to eq(project.ssh_url_to_repo) }
it { expect(data[:repository][:visibility_level]).to eq(project.visibility_level) }
it { expect(data[:total_commits_count]).to eq(3) }
+ it { expect(data[:added]).to eq(["gitlab-grack"]) }
+ it { expect(data[:modified]).to eq([".gitmodules", "files/ruby/popen.rb", "files/ruby/regex.rb"]) }
+ it { expect(data[:removed]).to eq([]) }
end
describe :build do
@@ -35,5 +38,8 @@ describe 'Gitlab::PushDataBuilder' do
it { expect(data[:ref]).to eq('refs/tags/v1.1.0') }
it { expect(data[:commits]).to be_empty }
it { expect(data[:total_commits_count]).to be_zero }
+ it { expect(data[:added]).to eq([]) }
+ it { expect(data[:modified]).to eq([]) }
+ it { expect(data[:removed]).to eq([]) }
end
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 3761732c37..2b36fc42e6 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -487,7 +487,7 @@ describe Notify do
subject { Notify.note_commit_email(recipient.id, note.id) }
it_behaves_like 'a note email'
- it_behaves_like 'an answer to an existing thread', 'commits'
+ it_behaves_like 'an answer to an existing thread', 'commit'
it 'has the correct subject' do
is_expected.to have_subject /#{commit.title} \(#{commit.short_id}\)/
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 80638fc8db..0f23e81ace 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -84,4 +84,23 @@ describe Group do
expect(group.avatar_type).to eq(["only images allowed"])
end
end
+
+ describe "public_profile?" do
+ it "returns true for public group" do
+ group = create(:group, public: true)
+ expect(group.public_profile?).to be_truthy
+ end
+
+ it "returns true for non-public group with public project" do
+ group = create(:group)
+ create(:project, :public, group: group)
+ expect(group.public_profile?).to be_truthy
+ end
+
+ it "returns false for non-public group with no public projects" do
+ group = create(:group)
+ create(:project, group: group)
+ expect(group.public_profile?).to be_falsy
+ end
+ end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 14c599c84b..c128781e29 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -79,6 +79,12 @@ describe MergeRequest do
expect(merge_request.commits).not_to be_empty
expect(merge_request.mr_and_commit_notes.count).to eq(2)
end
+
+ it "should include notes for commits from target project as well" do
+ create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit', project: merge_request.target_project)
+ expect(merge_request.commits).not_to be_empty
+ expect(merge_request.mr_and_commit_notes.count).to eq(3)
+ end
end
describe '#is_being_reassigned?' do
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 94802dcfb7..9f6cdeeaa9 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -223,7 +223,7 @@ describe ProjectWiki do
def create_temp_repo(path)
FileUtils.mkdir_p path
- system(*%W(git init --quiet --bare -- #{path}))
+ system(*%W(#{Gitlab.config.git.bin_path} init --quiet --bare -- #{path}))
end
def remove_temp_repo(path)
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 05e51532eb..319fa0a7c8 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -26,6 +26,15 @@ describe Repository do
it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
end
+ describe :find_commits_by_message do
+ subject { repository.find_commits_by_message('submodule').map{ |k| k.id } }
+
+ it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
+ it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') }
+ it { is_expected.to include('cfe32cf61b73a0d5e9f13e774abde7ff789b1660') }
+ it { is_expected.not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e') }
+ end
+
describe :blob_at do
context 'blank sha' do
subject { repository.blob_at(Gitlab::Git::BLANK_SHA, '.gitignore') }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 14323c0a1c..ad90886dd0 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -697,24 +697,24 @@ describe User do
@user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
end
- it "sorts users as recently_signed_in" do
+ it "sorts users by the recent sign-in time" do
expect(User.sort('recent_sign_in').first).to eq(@user)
end
- it "sorts users as late_signed_in" do
+ it "sorts users by the oldest sign-in time" do
expect(User.sort('oldest_sign_in').first).to eq(@user1)
end
- it "sorts users as recently_created" do
+ it "sorts users in descending order by their creation time" do
expect(User.sort('created_desc').first).to eq(@user)
end
- it "sorts users as late_created" do
+ it "sorts users in ascending order by their creation time" do
expect(User.sort('created_asc').first).to eq(@user1)
end
- it "sorts users by name when nil is passed" do
- expect(User.sort(nil).first).to eq(@user)
+ it "sorts users by id in descending order when nil is passed" do
+ expect(User.sort(nil).first).to eq(@user1)
end
end
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index 042e635256..8efa09f75f 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -19,6 +19,7 @@ describe API::API, api: true do
expect(response.status).to eq(200)
expect(json_response['file_path']).to eq(file_path)
expect(json_response['file_name']).to eq('popen.rb')
+ expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n")
end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 1149f7e798..faf6b77a46 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -36,8 +36,8 @@ describe API::API, api: true do
it 'should create a new annotated tag' do
# Identity must be set in .gitconfig to create annotated tag.
repo_path = project.repository.path_to_repo
- system(*%W(git --git-dir=#{repo_path} config user.name #{user.name}))
- system(*%W(git --git-dir=#{repo_path} config user.email #{user.email}))
+ system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.name #{user.name}))
+ system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.email #{user.email}))
post api("/projects/#{project.id}/repository/tags", user),
tag_name: 'v7.1.0',
diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb
index d7242d684c..cda7d0c4a5 100644
--- a/spec/services/ci/image_for_build_service_spec.rb
+++ b/spec/services/ci/image_for_build_service_spec.rb
@@ -4,8 +4,9 @@ module Ci
describe ImageForBuildService do
let(:service) { ImageForBuildService.new }
let(:project) { FactoryGirl.create(:ci_project) }
- let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
- let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project, ref: 'master') }
+ let(:gl_project) { FactoryGirl.create(:project, gitlab_ci_project: project) }
+ let(:commit_sha) { gl_project.commit('master').sha }
+ let(:commit) { gl_project.ensure_ci_commit(commit_sha) }
let(:build) { FactoryGirl.create(:ci_build, commit: commit) }
describe :execute do
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index d12ba25b71..787670e929 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -96,15 +96,15 @@ module TestEnv
clone_url = "https://gitlab.com/gitlab-org/#{repo_name}.git"
unless File.directory?(repo_path)
- system(*%W(git clone -q #{clone_url} #{repo_path}))
+ system(*%W(#{Gitlab.config.git.bin_path} clone -q #{clone_url} #{repo_path}))
end
Dir.chdir(repo_path) do
branch_sha.each do |branch, sha|
# Try to reset without fetching to avoid using the network.
- reset = %W(git update-ref refs/heads/#{branch} #{sha})
+ reset = %W(#{Gitlab.config.git.bin_path} update-ref refs/heads/#{branch} #{sha})
unless system(*reset)
- if system(*%w(git fetch origin))
+ if system(*%W(#{Gitlab.config.git.bin_path} fetch origin))
unless system(*reset)
raise 'The fetched test seed '\
'does not contain the required revision.'
@@ -117,7 +117,7 @@ module TestEnv
end
# We must copy bare repositories because we will push to them.
- system(git_env, *%W(git clone -q --bare #{repo_path} #{repo_path_bare}))
+ system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare}))
end
def copy_repo(project)
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 3be7dd4e52..386ac9c837 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -55,6 +55,7 @@ describe 'gitlab:app namespace rake task' do
expect(Rake::Task["gitlab:backup:db:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:backup:repo:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:backup:builds:restore"]).to receive(:invoke)
+ expect(Rake::Task["gitlab:backup:uploads:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:shell:setup"]).to receive(:invoke)
expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error
end
@@ -112,14 +113,14 @@ describe 'gitlab:app namespace rake task' do
it 'should set correct permissions on the tar contents' do
tar_contents, exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{@backup_tar} db uploads repositories builds}
+ %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz}
)
expect(exit_status).to eq(0)
expect(tar_contents).to match('db/')
- expect(tar_contents).to match('uploads/')
+ expect(tar_contents).to match('uploads.tar.gz')
expect(tar_contents).to match('repositories/')
- expect(tar_contents).to match('builds/')
- expect(tar_contents).not_to match(/^.{4,9}[rwx].* (db|uploads|repositories|builds)\/$/)
+ expect(tar_contents).to match('builds.tar.gz')
+ expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz)\/$/)
end
it 'should delete temp directories' do
@@ -160,12 +161,12 @@ describe 'gitlab:app namespace rake task' do
it "does not contain skipped item" do
tar_contents, _exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{@backup_tar} db uploads repositories builds}
+ %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz}
)
expect(tar_contents).to match('db/')
- expect(tar_contents).to match('uploads/')
- expect(tar_contents).to match('builds/')
+ expect(tar_contents).to match('uploads.tar.gz')
+ expect(tar_contents).to match('builds.tar.gz')
expect(tar_contents).not_to match('repositories/')
end
diff --git a/spec/workers/stuck_ci_builds_worker_spec.rb b/spec/workers/stuck_ci_builds_worker_spec.rb
new file mode 100644
index 0000000000..f9d87d9701
--- /dev/null
+++ b/spec/workers/stuck_ci_builds_worker_spec.rb
@@ -0,0 +1,44 @@
+require "spec_helper"
+
+describe StuckCiBuildsWorker do
+ let!(:build) { create :ci_build }
+
+ subject do
+ build.reload
+ build.status
+ end
+
+ %w(pending running).each do |status|
+ context "#{status} build" do
+ before do
+ build.update!(status: status)
+ end
+
+ it 'gets dropped if it was updated over 2 days ago' do
+ build.update!(updated_at: 2.day.ago)
+ StuckCiBuildsWorker.new.perform
+ is_expected.to eq('failed')
+ end
+
+ it "is still #{status}" do
+ build.update!(updated_at: 1.minute.ago)
+ StuckCiBuildsWorker.new.perform
+ is_expected.to eq(status)
+ end
+ end
+ end
+
+ %w(success failed canceled).each do |status|
+ context "#{status} build" do
+ before do
+ build.update!(status: status)
+ end
+
+ it "is still #{status}" do
+ build.update!(updated_at: 2.day.ago)
+ StuckCiBuildsWorker.new.perform
+ is_expected.to eq(status)
+ end
+ end
+ end
+end
diff --git a/vendor/assets/javascripts/clipboard.js b/vendor/assets/javascripts/clipboard.js
new file mode 100644
index 0000000000..1b1f4f0bd6
--- /dev/null
+++ b/vendor/assets/javascripts/clipboard.js
@@ -0,0 +1,621 @@
+/*!
+ * clipboard.js v1.4.2
+ * https://zenorocha.github.io/clipboard.js
+ *
+ * Licensed MIT © Zeno Rocha
+ */
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Clipboard = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o