Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Vosmaer <contact@jacobvosmaer.nl>2015-07-29 16:44:04 +0300
committerJacob Vosmaer <contact@jacobvosmaer.nl>2015-07-29 16:44:04 +0300
commit05b518aa4d5a690ab90f7026b3684659c9d51fa9 (patch)
treed34d37bcbe77cf73007d1d272e05c7ca94113f07
parent097a8952d0991b42752a84aedd472aa8291717cf (diff)
parent8bda433734394af7e3858c0804b378a6d1313a84 (diff)
Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq into backup-archive-permissions
-rw-r--r--CHANGELOG22
-rw-r--r--Gemfile3
-rw-r--r--Gemfile.lock10
-rw-r--r--app/assets/images/auth_buttons/bitbucket_64.png (renamed from app/assets/images/authbuttons/bitbucket_64.png)bin2163 -> 2163 bytes
-rw-r--r--app/assets/images/auth_buttons/github_64.pngbin0 -> 2625 bytes
-rw-r--r--app/assets/images/auth_buttons/gitlab_64.pngbin0 -> 2849 bytes
-rw-r--r--app/assets/images/auth_buttons/google_64.png (renamed from app/assets/images/authbuttons/google_64.png)bin5281 -> 5281 bytes
-rw-r--r--app/assets/images/auth_buttons/twitter_64.png (renamed from app/assets/images/authbuttons/twitter_64.png)bin4835 -> 4835 bytes
-rw-r--r--app/assets/images/authbuttons/github_64.pngbin4196 -> 0 bytes
-rw-r--r--app/assets/images/authbuttons/gitlab_64.pngbin6559 -> 0 bytes
-rw-r--r--app/assets/javascripts/application.js.coffee7
-rw-r--r--app/assets/javascripts/diff.js.coffee4
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee10
-rw-r--r--app/assets/javascripts/notes.js.coffee1
-rw-r--r--app/assets/stylesheets/generic/common.scss2
-rw-r--r--app/assets/stylesheets/pages/diff.scss11
-rw-r--r--app/assets/stylesheets/pages/notes.scss4
-rw-r--r--app/controllers/application_controller.rb6
-rw-r--r--app/controllers/import/bitbucket_controller.rb1
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb5
-rw-r--r--app/controllers/projects/refs_controller.rb6
-rw-r--r--app/controllers/sessions_controller.rb2
-rw-r--r--app/helpers/auth_helper.rb50
-rw-r--r--app/helpers/blob_helper.rb8
-rw-r--r--app/helpers/emails_helper.rb4
-rw-r--r--app/helpers/oauth_helper.rb34
-rw-r--r--app/helpers/profile_helper.rb13
-rw-r--r--app/helpers/projects_helper.rb3
-rw-r--r--app/models/ability.rb3
-rw-r--r--app/models/concerns/issuable.rb10
-rw-r--r--app/models/merge_request.rb4
-rw-r--r--app/models/user.rb4
-rw-r--r--app/services/files/base_service.rb2
-rw-r--r--app/services/issuable_base_service.rb6
-rw-r--r--app/services/issues/base_service.rb4
-rw-r--r--app/services/merge_requests/auto_merge_service.rb10
-rw-r--r--app/services/merge_requests/base_service.rb6
-rw-r--r--app/services/projects/create_service.rb2
-rw-r--r--app/views/admin/identities/_form.html.haml3
-rw-r--r--app/views/admin/identities/_identity.html.haml2
-rw-r--r--app/views/devise/sessions/_new_ldap.html.haml2
-rw-r--r--app/views/devise/shared/_omniauth_box.html.haml8
-rw-r--r--app/views/devise/shared/_signin_box.html.haml2
-rw-r--r--app/views/events/_event.html.haml15
-rw-r--r--app/views/layouts/notify.html.haml2
-rw-r--r--app/views/profiles/accounts/show.html.haml14
-rw-r--r--app/views/profiles/two_factor_auths/new.html.haml2
-rw-r--r--app/views/projects/blob/diff.html.haml2
-rw-r--r--app/views/projects/diffs/_text_file.html.haml3
-rw-r--r--app/views/projects/diffs/_warning.html.haml2
-rw-r--r--app/views/projects/issues/_issue.html.haml73
-rw-r--r--app/views/projects/merge_requests/_show.html.haml6
-rw-r--r--app/views/projects/notes/_edit_form.html.haml5
-rw-r--r--app/views/projects/notes/_form.html.haml14
-rw-r--r--app/views/projects/notes/_hints.html.haml9
-rw-r--r--app/views/projects/notes/_note.html.haml7
-rw-r--r--app/views/projects/refs/logs_tree.js.haml8
-rw-r--r--app/views/projects/tree/_tree.html.haml2
-rw-r--r--app/views/projects/wikis/show.html.haml6
-rw-r--r--app/views/shared/issuable/_context.html.haml4
-rw-r--r--app/views/shared/issuable/_form.html.haml2
-rw-r--r--config/gitlab.yml.example25
-rw-r--r--db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb6
-rw-r--r--doc/gitlab-basics/README.md4
-rw-r--r--doc/gitlab-basics/add-file.md31
-rw-r--r--doc/integration/gitlab_actions.pngbin17321 -> 0 bytes
-rw-r--r--doc/integration/gitlab_buttons_in_gmail.md28
-rw-r--r--doc/integration/omniauth.md2
-rw-r--r--doc/permissions/permissions.md1
-rw-r--r--doc/release/monthly.md10
-rw-r--r--doc/workflow/importing/README.md5
-rw-r--r--features/project/source/browse_files.feature7
-rw-r--r--features/steps/admin/users.rb9
-rw-r--r--features/steps/project/source/browse_files.rb17
-rw-r--r--lib/api/merge_requests.rb2
-rw-r--r--lib/gitlab/backend/grack_auth.rb11
-rw-r--r--lib/gitlab/backend/shell_env.rb11
-rw-r--r--lib/gitlab/bitbucket_import/client.rb21
-rw-r--r--lib/gitlab/o_auth/provider.rb28
-rw-r--r--lib/gitlab/satellite/merge_action.rb2
-rw-r--r--lib/redcarpet/render/gitlab_html.rb8
-rw-r--r--lib/rouge/formatters/html_gitlab.rb168
-rw-r--r--lib/support/nginx/gitlab25
-rw-r--r--lib/support/nginx/gitlab-ssl25
-rw-r--r--lib/tasks/gitlab/mail_google_schema_whitelisting.rake73
-rw-r--r--lib/tasks/gitlab/update_commit_count.rake20
-rw-r--r--lib/unfold_form.rb1
-rw-r--r--spec/controllers/users_controller_spec.rb35
-rw-r--r--spec/features/security/admin_access_spec.rb (renamed from spec/features/admin/security_spec.rb)2
-rw-r--r--spec/features/security/dashboard_access_spec.rb2
-rw-r--r--spec/features/security/group/group_access_spec.rb98
-rw-r--r--spec/features/security/group/internal_group_access_spec.rb82
-rw-r--r--spec/features/security/group/mixed_group_access_spec.rb83
-rw-r--r--spec/features/security/group/public_group_access_spec.rb82
-rw-r--r--spec/features/security/group_access_spec.rb284
-rw-r--r--spec/features/security/profile_access_spec.rb14
-rw-r--r--spec/features/security/project/internal_access_spec.rb2
-rw-r--r--spec/features/security/project/private_access_spec.rb2
-rw-r--r--spec/features/security/project/public_access_spec.rb3
-rw-r--r--spec/helpers/auth_helper_spec.rb20
-rw-r--r--spec/helpers/oauth_helper_spec.rb20
-rw-r--r--spec/helpers/projects_helper_spec.rb20
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js.coffee6
-rw-r--r--spec/models/user_spec.rb12
-rw-r--r--spec/requests/api/merge_requests_spec.rb6
-rw-r--r--spec/services/projects/create_service_spec.rb12
-rw-r--r--spec/support/matchers.rb66
-rw-r--r--spec/support/matchers/access_matchers.rb54
-rw-r--r--spec/support/matchers/include_module.rb13
-rw-r--r--spec/support/matchers/is_within.rb9
-rw-r--r--spec/support/test_env.rb3
111 files changed, 1132 insertions, 788 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3570bb6df51..6e3a7e8669b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,8 +1,14 @@
Please view this file on the master branch, on stable branches it's out of date.
v 7.14.0 (unreleased)
+ - Upgrade gitlab_git to version 7.2.6 to fix Error 500 when creating network graphs (Stan Hu)
+ - Fix URL used for refreshing notes if relative_url is present (Bartłomiej Święcki)
+ - Fix commit data retrieval when branch name has single quotes (Stan Hu)
+ - Fix Error 500 when browsing projects with no HEAD (Stan Hu)
+ - Add rake task 'gitlab:update_commit_count' (Daniel Gerhardt)
- Fix full screen mode for snippet comments (Daniel Gerhardt)
- Fix 404 error in files view after deleting the last file in a repository (Stan Hu)
+ - Fix the "Reload with full diff" URL button (Stan Hu)
- Fix label read access for unauthenticated users (Daniel Gerhardt)
- Fix access to disabled features for unauthenticated users (Daniel Gerhardt)
- Fix OAuth provider bug where GitLab would not go return to the redirect_uri after sign-in (Stan Hu)
@@ -14,7 +20,22 @@ v 7.14.0 (unreleased)
- Allow custom backup archive permissions
v 7.13.0 (unreleased)
+ - Add fetch command to the MR page
+ - Fix bug causing Bitbucket importer to crash when OAuth application had been removed.
+
+v 7.13.1
+ - Fix: Label modifications are not reflected in existing notes and in the issue list
+ - Fix: Label not shown in the Issue list, although it's set through web interface
+ - Fix: Group/project references are linked incorrectly
+ - Improve documentation
+ - Fix of migration: Check if session_expire_delay column exists before adding the column
+ - Fix: ActionView::Template::Error
+ - Fix: "Create Merge Request" isn't always shown in event for newly pushed branch
+ - Fix bug causing "Remove source-branch" option not to work for merge requests from the same project.
+
+v 7.13.0
- Remove repository graph log to fix slow cache updates after push event (Stan Hu)
+ - Return comments in created order in merge request API (Stan Hu)
- Only enable HSTS header for HTTPS and port 443 (Stan Hu)
- Fix user autocomplete for unauthenticated users accessing public projects (Stan Hu)
- Fix redirection to home page URL for unauthorized users (Daniel Gerhardt)
@@ -68,6 +89,7 @@ v 7.12.2
- Faster automerge check and merge itself when source and target branches are in same repository
- Audit log for user authentication
- Fix transferring of project to another group using the API.
+ - Allow custom label to be set for authentication providers.
v 7.12.1
- Fix error when deleting a user who has projects (Stan Hu)
diff --git a/Gemfile b/Gemfile
index ba32feba3e7..1c49a603798 100644
--- a/Gemfile
+++ b/Gemfile
@@ -38,7 +38,7 @@ gem "browser", '~> 0.8.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem "gitlab_git", '~> 7.2.5'
+gem "gitlab_git", '~> 7.2.6'
# Ruby/Rack Git Smart-HTTP Server Handler
# GitLab fork with a lot of changes (improved thread-safety, better memory usage etc)
@@ -272,4 +272,3 @@ end
gem "newrelic_rpm"
gem 'octokit', '3.7.0'
-gem "rugments", "~> 1.0.0.beta8"
diff --git a/Gemfile.lock b/Gemfile.lock
index 6e571072a4c..44365017edc 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -271,7 +271,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.1.0)
gemojione (~> 2.0)
- gitlab_git (7.2.5)
+ gitlab_git (7.2.6)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
@@ -288,7 +288,7 @@ GEM
github-markup (~> 1.3.1)
gollum-grit_adapter (~> 0.1, >= 0.1.1)
nokogiri (~> 1.6.4)
- rouge (~> 1.7.4)
+ rouge (~> 1.9)
sanitize (~> 2.1.0)
stringex (~> 2.5.1)
gon (5.0.1)
@@ -536,7 +536,7 @@ GEM
netrc (~> 0.7)
rinku (1.7.3)
rotp (1.6.1)
- rouge (1.7.7)
+ rouge (1.9.1)
rqrcode (0.4.2)
rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2)
@@ -579,7 +579,6 @@ GEM
rubyntlm (0.5.0)
rubypants (0.2.0)
rugged (0.22.2)
- rugments (1.0.0.beta8)
safe_yaml (1.0.4)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
@@ -784,7 +783,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.2)
gitlab-linguist (~> 3.0.1)
gitlab_emoji (~> 0.1)
- gitlab_git (~> 7.2.5)
+ gitlab_git (~> 7.2.6)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.1)
gollum-lib (~> 4.0.2)
@@ -836,7 +835,6 @@ DEPENDENCIES
rqrcode-rails3
rspec-rails (~> 3.3.0)
rubocop (= 0.28.0)
- rugments (~> 1.0.0.beta8)
sanitize (~> 2.0)
sass-rails (~> 4.0.5)
sdoc
diff --git a/app/assets/images/authbuttons/bitbucket_64.png b/app/assets/images/auth_buttons/bitbucket_64.png
index 4b90a57bc7d..4b90a57bc7d 100644
--- a/app/assets/images/authbuttons/bitbucket_64.png
+++ b/app/assets/images/auth_buttons/bitbucket_64.png
Binary files differ
diff --git a/app/assets/images/auth_buttons/github_64.png b/app/assets/images/auth_buttons/github_64.png
new file mode 100644
index 00000000000..182a1a3f734
--- /dev/null
+++ b/app/assets/images/auth_buttons/github_64.png
Binary files differ
diff --git a/app/assets/images/auth_buttons/gitlab_64.png b/app/assets/images/auth_buttons/gitlab_64.png
new file mode 100644
index 00000000000..99a40583b3a
--- /dev/null
+++ b/app/assets/images/auth_buttons/gitlab_64.png
Binary files differ
diff --git a/app/assets/images/authbuttons/google_64.png b/app/assets/images/auth_buttons/google_64.png
index fb64f8bee68..fb64f8bee68 100644
--- a/app/assets/images/authbuttons/google_64.png
+++ b/app/assets/images/auth_buttons/google_64.png
Binary files differ
diff --git a/app/assets/images/authbuttons/twitter_64.png b/app/assets/images/auth_buttons/twitter_64.png
index e3bd9169a34..e3bd9169a34 100644
--- a/app/assets/images/authbuttons/twitter_64.png
+++ b/app/assets/images/auth_buttons/twitter_64.png
Binary files differ
diff --git a/app/assets/images/authbuttons/github_64.png b/app/assets/images/authbuttons/github_64.png
deleted file mode 100644
index dc7c03d1005..00000000000
--- a/app/assets/images/authbuttons/github_64.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/authbuttons/gitlab_64.png b/app/assets/images/authbuttons/gitlab_64.png
deleted file mode 100644
index 31281a19444..00000000000
--- a/app/assets/images/authbuttons/gitlab_64.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 8b041c490d8..bb0a0c51fd4 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -164,9 +164,10 @@ $ ->
$('.account-box').hover -> $(@).toggleClass('hover')
# Commit show suppressed diff
- $(".diff-content").on "click", ".supp_diff_link", ->
- $(@).next('table').show()
- $(@).remove()
+ $(document).on 'click', '.diff-content .js-show-suppressed-diff', ->
+ $container = $(@).parent()
+ $container.next('table').show()
+ $container.remove()
$('.navbar-toggle').on 'click', ->
$('.header-content .title').toggle()
diff --git a/app/assets/javascripts/diff.js.coffee b/app/assets/javascripts/diff.js.coffee
index 069f91c30e1..6d9b364cb8d 100644
--- a/app/assets/javascripts/diff.js.coffee
+++ b/app/assets/javascripts/diff.js.coffee
@@ -31,6 +31,10 @@ class @Diff
bottom: unfoldBottom
offset: offset
unfold: unfold
+ # indent is used to compensate for single space indent to fit
+ # '+' and '-' prepended to diff lines,
+ # see https://gitlab.com/gitlab-org/gitlab-ce/issues/707
+ indent: 1
$.get(link, params, (response) =>
target.parent().replaceWith(response)
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index a132a0a9dcc..19a07b6a033 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -49,12 +49,6 @@ class @MergeRequestTabs
# Store the `location` object, allowing for easier stubbing in tests
@_location = location
- switch @opts.action
- when 'commits'
- @commitsLoaded = true
- when 'diffs'
- @diffsLoaded = true
-
@bindEvents()
@activateTab(@opts.action)
@@ -102,7 +96,7 @@ class @MergeRequestTabs
action = 'notes' if action == 'show'
# Remove a trailing '/commits' or '/diffs'
- new_state = @_location.pathname.replace(/\/(commits|diffs)\/?$/, '')
+ new_state = @_location.pathname.replace(/\/(commits|diffs)(\.html)?\/?$/, '')
# Append the new action if we're on a tab other than 'notes'
unless action == 'notes'
@@ -133,7 +127,7 @@ class @MergeRequestTabs
return if @diffsLoaded
@_get
- url: "#{source}.json"
+ url: "#{source}.json" + @_location.search
success: (data) =>
document.getElementById('diffs').innerHTML = data.html
@diffsLoaded = true
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index bcff7bcc49e..0021d17d85e 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -10,7 +10,6 @@ class @Notes
constructor: (notes_url, note_ids, last_fetched_at, view) ->
@notes_url = notes_url
- @notes_url = gon.relative_url_root + @notes_url if gon.relative_url_root?
@note_ids = note_ids
@last_fetched_at = last_fetched_at
@view = view
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 961ac793de2..d36530169a9 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -184,7 +184,7 @@ li.note {
}
}
-.supp_diff_link,
+.show-suppressed-diff,
.show-all-commits {
cursor: pointer;
}
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index af6ea58382f..1557c243db5 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -65,6 +65,17 @@
color: #777;
}
+ .suppressed-container {
+ padding: ($padding-base-vertical + 5px) $padding-base-horizontal;
+ text-align: center;
+
+ // "Changes suppressed. Click to show." link
+ .show-suppressed-diff {
+ font-size: 110%;
+ font-weight: bold;
+ }
+ }
+
table {
width: 100%;
font-family: $monospace_font;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 4da65b28743..85c828ec1ad 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -37,7 +37,7 @@ ul.notes {
font-size: 13px;
a {
- @extend .cgray;
+ @extend .cgray;
&:hover {
text-decoration: underline;
@@ -105,6 +105,8 @@ ul.notes {
}
hr {
+ // Darken 'whitesmoke' a bit to make it more visible in note bodies
+ border-color: darken(#F5F5F5, 8%);
margin: 10px 0;
}
}
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 362b03e0d5e..3ce8dbc9407 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -299,14 +299,14 @@ class ApplicationController < ActionController::Base
end
def github_import_enabled?
- OauthHelper.enabled_oauth_providers.include?(:github)
+ Gitlab::OAuth::Provider.enabled?(:github)
end
def gitlab_import_enabled?
- OauthHelper.enabled_oauth_providers.include?(:gitlab)
+ Gitlab::OAuth::Provider.enabled?(:gitlab)
end
def bitbucket_import_enabled?
- OauthHelper.enabled_oauth_providers.include?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
+ Gitlab::OAuth::Provider.enabled?(:bitbucket) && Gitlab::BitbucketImport.public_key.present?
end
end
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index ca78a4aaa8e..af0b841f0b7 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -3,6 +3,7 @@ class Import::BitbucketController < Import::BaseController
before_action :bitbucket_auth, except: :callback
rescue_from OAuth::Error, with: :bitbucket_unauthorized
+ rescue_from Gitlab::BitbucketImport::Client::Unauthorized, with: :bitbucket_unauthorized
def callback
request_token = session.delete(:oauth_request_token)
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index fd51b380da2..523264b8ea9 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -72,10 +72,11 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end
end
rescue Gitlab::OAuth::SignupDisabledError => e
- message = "Signing in using your #{oauth['provider']} account without a pre-existing GitLab account is not allowed."
+ label = Gitlab::OAuth::Provider.label_for(oauth['provider'])
+ message = "Signing in using your #{label} account without a pre-existing GitLab account is not allowed."
if current_application_settings.signup_enabled?
- message << " Create a GitLab account first, and then connect it to your #{oauth['provider']} account."
+ message << " Create a GitLab account first, and then connect it to your #{label} account."
end
flash[:notice] = message
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index d83561cf32a..6080c849c8d 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -1,5 +1,6 @@
class Projects::RefsController < Projects::ApplicationController
include ExtractsPath
+ include TreeHelper
before_action :require_non_empty_project
before_action :assign_ref_vars
@@ -60,6 +61,11 @@ class Projects::RefsController < Projects::ApplicationController
}
end
+ if @logs.present?
+ @log_url = namespace_project_tree_url(@project.namespace, @project, tree_join(@ref, @path || '/'))
+ @more_log_url = logs_file_namespace_project_ref_path(@project.namespace, @project, @ref, @path || '', offset: (@offset + @limit))
+ end
+
respond_to do |format|
format.html { render_404 }
format.js
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 89629bc0581..796cbe4c58c 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -90,7 +90,7 @@ class SessionsController < Devise::SessionsController
# Prevent alert from popping up on the first page shown after authentication.
flash[:alert] = nil
- redirect_to omniauth_authorize_path(:user, provider.to_sym)
+ redirect_to user_omniauth_authorize_path(provider.to_sym)
end
def valid_otp_attempt?(user)
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
new file mode 100644
index 00000000000..0e7a37b4cc6
--- /dev/null
+++ b/app/helpers/auth_helper.rb
@@ -0,0 +1,50 @@
+module AuthHelper
+ PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
+ FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos'].freeze
+
+ def ldap_enabled?
+ Gitlab.config.ldap.enabled
+ end
+
+ def provider_has_icon?(name)
+ PROVIDERS_WITH_ICONS.include?(name.to_s)
+ end
+
+ def auth_providers
+ Gitlab::OAuth::Provider.providers
+ end
+
+ def label_for_provider(name)
+ Gitlab::OAuth::Provider.label_for(name)
+ end
+
+ def form_based_provider?(name)
+ FORM_BASED_PROVIDERS.any? { |pattern| pattern === name.to_s }
+ end
+
+ def form_based_providers
+ auth_providers.select { |provider| form_based_provider?(provider) }
+ end
+
+ def button_based_providers
+ auth_providers.reject { |provider| form_based_provider?(provider) }
+ end
+
+ def provider_image_tag(provider, size = 64)
+ label = label_for_provider(provider)
+
+ if provider_has_icon?(provider)
+ file_name = "#{provider.to_s.split('_').first}_#{size}.png"
+
+ image_tag(image_path("auth_buttons/#{file_name}"), alt: label, title: "Sign in with #{label}")
+ else
+ label
+ end
+ end
+
+ def auth_active?(provider)
+ current_user.identities.exists?(provider: provider.to_s)
+ end
+
+ extend self
+end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 50df3801703..77d99140c43 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -1,6 +1,6 @@
module BlobHelper
def highlight(blob_name, blob_content, nowrap: false, continue: false)
- @formatter ||= Rugments::Formatters::HTML.new(
+ @formatter ||= Rouge::Formatters::HTMLGitlab.new(
nowrap: nowrap,
cssclass: 'code highlight',
lineanchors: true,
@@ -8,11 +8,11 @@ module BlobHelper
)
begin
- @lexer ||= Rugments::Lexer.guess(filename: blob_name, source: blob_content).new
+ @lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new
result = @formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe
rescue
- lexer = Rugments::Lexers::PlainText
- result = @formatter.format(lexer.lex(blob_content)).html_safe
+ @lexer = Rouge::Lexers::PlainText
+ result = @formatter.format(@lexer.lex(blob_content)).html_safe
end
result
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index 128de18bc47..45788ba95ac 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -31,8 +31,8 @@ module EmailsHelper
end
def color_email_diff(diffcontent)
- formatter = Rugments::Formatters::HTML.new(cssclass: "highlight", inline_theme: :github)
- lexer = Rugments::Lexers::Diff.new
+ formatter = Rouge::Formatters::HTML.new(css_class: 'highlight', inline_theme: 'github')
+ lexer = Rouge::Lexers::Diff
raw formatter.format(lexer.lex(diffcontent))
end
diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb
deleted file mode 100644
index 2fdca13ed40..00000000000
--- a/app/helpers/oauth_helper.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-module OauthHelper
- def ldap_enabled?
- Gitlab.config.ldap.enabled
- end
-
- def default_providers
- [:twitter, :github, :gitlab, :bitbucket, :google_oauth2, :ldap]
- end
-
- def enabled_oauth_providers
- Devise.omniauth_providers
- end
-
- def enabled_social_providers
- enabled_oauth_providers.select do |name|
- [:saml, :twitter, :gitlab, :github, :bitbucket, :google_oauth2].include?(name.to_sym)
- end
- end
-
- def additional_providers
- enabled_oauth_providers.reject{|provider| provider.to_s.starts_with?('ldap')}
- end
-
- def oauth_image_tag(provider, size = 64)
- file_name = "#{provider.to_s.split('_').first}_#{size}.png"
- image_tag(image_path("authbuttons/#{file_name}"), alt: "Sign in with #{provider.to_s.titleize}")
- end
-
- def oauth_active?(provider)
- current_user.identities.exists?(provider: provider.to_s)
- end
-
- extend self
-end
diff --git a/app/helpers/profile_helper.rb b/app/helpers/profile_helper.rb
deleted file mode 100644
index 780c7cd5133..00000000000
--- a/app/helpers/profile_helper.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-module ProfileHelper
- def show_profile_username_tab?
- current_user.can_change_username?
- end
-
- def show_profile_social_tab?
- enabled_social_providers.any?
- end
-
- def show_profile_remove_tab?
- signup_enabled?
- end
-end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 3cd52b381bd..a675a292432 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -278,7 +278,8 @@ module ProjectsHelper
end
def readme_cache_key
- [@project.id, @project.commit.sha, "readme"].join('-')
+ sha = @project.commit.try(:sha) || 'nil'
+ [@project.id, sha, "readme"].join('-')
end
def round_commit_count(project)
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 9258d981ac9..6a8f683bc89 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -140,12 +140,13 @@ class Ability
:create_project_snippet,
:update_issue,
:admin_issue,
- :admin_label,
+ :admin_label
]
end
def project_dev_rules
project_report_rules + [
+ :admin_merge_request,
:create_merge_request,
:create_wiki,
:push_code
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 97846b06d72..c21e7fd0e3b 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -159,6 +159,16 @@ module Issuable
end
end
+ # Convert this Issuable class name to a format usable by Ability definitions
+ #
+ # Examples:
+ #
+ # issuable.class # => MergeRequest
+ # issuable.to_ability_name # => "merge_request"
+ def to_ability_name
+ self.class.to_s.underscore
+ end
+
private
def filter_superceded_votes(votes, notes)
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 53b3fc10ccb..1ef76d16700 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -235,6 +235,10 @@ class MergeRequest < ActiveRecord::Base
execute(self, commit_message)
end
+ def remove_source_branch?
+ self.should_remove_source_branch && !self.source_project.root_ref?(self.source_branch) && !self.for_fork?
+ end
+
def open?
opened? || reopened?
end
diff --git a/app/models/user.rb b/app/models/user.rb
index fb330ff7185..4a10520b209 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -274,6 +274,10 @@ class User < ActiveRecord::Base
value: login.to_s.downcase).first
end
+ def find_by_username!(username)
+ find_by!('lower(username) = ?', username.downcase)
+ end
+
def by_username_or_id(name_or_id)
where('users.username = ? OR users.id = ?', name_or_id.to_s, name_or_id.to_i).first
end
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index f587ee266da..646784f2d9d 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -39,7 +39,7 @@ module Files
def after_commit(sha, branch)
commit = repository.commit(sha)
- full_ref = 'refs/heads/' + branch
+ full_ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch}"
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index f1ef5ca84fe..15b3825f96a 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -27,8 +27,10 @@ class IssuableBaseService < BaseService
old_branch, new_branch)
end
- def filter_params
- unless can?(current_user, :admin_issue, project)
+ def filter_params(issuable_ability_name = :issue)
+ ability = :"admin_#{issuable_ability_name}"
+
+ unless can?(current_user, ability, project)
params.delete(:milestone_id)
params.delete(:label_ids)
params.delete(:assignee_id)
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index c3ca04a4343..770f32de944 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -10,6 +10,10 @@ module Issues
private
+ def filter_params
+ super(:issue)
+ end
+
def execute_hooks(issue, action = 'open')
issue_data = hook_data(issue, action)
issue.project.execute_hooks(issue_data, :issue_hooks)
diff --git a/app/services/merge_requests/auto_merge_service.rb b/app/services/merge_requests/auto_merge_service.rb
index df793fc997d..db824d452d0 100644
--- a/app/services/merge_requests/auto_merge_service.rb
+++ b/app/services/merge_requests/auto_merge_service.rb
@@ -37,6 +37,14 @@ module MergeRequests
# Merge local branches using rugged instead of satellites
if sha = commit
after_commit(sha, merge_request.target_branch)
+
+ if merge_request.remove_source_branch?
+ DeleteBranchService.new(merge_request.source_project, current_user).execute(merge_request.source_branch)
+ end
+
+ true
+ else
+ false
end
end
end
@@ -55,7 +63,7 @@ module MergeRequests
def after_commit(sha, branch)
commit = repository.commit(sha)
- full_ref = 'refs/heads/' + branch
+ full_ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch}"
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index e455fe95791..7b306a8a531 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -20,5 +20,11 @@ module MergeRequests
merge_request.project.execute_services(merge_data, :merge_request_hooks)
end
end
+
+ private
+
+ def filter_params
+ super(:merge_request)
+ end
end
end
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 011f6f6145e..b35aed005da 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -85,6 +85,8 @@ module Projects
@project.create_wiki if @project.wiki_enabled?
+ @project.build_missing_services
+
event_service.create_project(@project, current_user)
system_hook_service.execute_hooks_for(@project, :create)
diff --git a/app/views/admin/identities/_form.html.haml b/app/views/admin/identities/_form.html.haml
index 0525552ebf8..3a788558226 100644
--- a/app/views/admin/identities/_form.html.haml
+++ b/app/views/admin/identities/_form.html.haml
@@ -8,7 +8,8 @@
.form-group
= f.label :provider, class: 'control-label'
.col-sm-10
- = f.select :provider, Gitlab::OAuth::Provider.names, { allow_blank: false }, class: 'form-control'
+ - values = Gitlab::OAuth::Provider.providers.map { |name| ["#{Gitlab::OAuth::Provider.label_for(name)} (#{name})", name] }
+ = f.select :provider, values, { allow_blank: false }, class: 'form-control'
.form-group
= f.label :extern_uid, "Identifier", class: 'control-label'
.col-sm-10
diff --git a/app/views/admin/identities/_identity.html.haml b/app/views/admin/identities/_identity.html.haml
index 671c4fbc677..7362d904b94 100644
--- a/app/views/admin/identities/_identity.html.haml
+++ b/app/views/admin/identities/_identity.html.haml
@@ -1,6 +1,6 @@
%tr
%td
- = identity.provider
+ = "#{Gitlab::OAuth::Provider.label_for(identity.provider)} (#{identity.provider})"
%td
= identity.extern_uid
%td
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index 6ec741e4882..689cd6ed665 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -6,4 +6,4 @@
%label{for: "remember_me"}
= check_box_tag :remember_me, '1', false, id: 'remember_me'
%span Remember me
- = button_tag "#{server['label']} Sign in", class: "btn-save btn"
+ = button_tag "Sign in", class: "btn-save btn"
diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml
index f8ba9d80ae8..ecf680e7b23 100644
--- a/app/views/devise/shared/_omniauth_box.html.haml
+++ b/app/views/devise/shared/_omniauth_box.html.haml
@@ -1,10 +1,8 @@
%p
%span.light
Sign in with &nbsp;
- - providers = additional_providers
+ - providers = button_based_providers
- providers.each do |provider|
%span.light
- - if default_providers.include?(provider)
- = link_to oauth_image_tag(provider), omniauth_authorize_path(resource_name, provider), method: :post, class: 'oauth-image-link'
- - else
- = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), method: :post, class: "btn", "data-no-turbolink" => "true"
+ - has_icon = provider_has_icon?(provider)
+ = link_to provider_image_tag(provider), user_omniauth_authorize_path(provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn'), "data-no-turbolink" => "true"
diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml
index c76574db457..bb5e479697d 100644
--- a/app/views/devise/shared/_signin_box.html.haml
+++ b/app/views/devise/shared/_signin_box.html.haml
@@ -6,7 +6,7 @@
.login-heading
%h3 Sign in
.login-body
- - if ldap_enabled?
+ - if form_based_providers.any?
%ul.nav.nav-tabs
- @ldap_servers.each_with_index do |server, i|
%li{class: (:active if i.zero?)}
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index b8409f64665..5ab5ffc238c 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -8,11 +8,10 @@
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
= render "events/event/created_project", event: event
- else
- = cache event do
- = image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
- - if event.push?
- = render "events/event/push", event: event
- - elsif event.commented?
- = render "events/event/note", event: event
- - else
- = render "events/event/common", event: event
+ = image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
+ - if event.push?
+ = render "events/event/push", event: event
+ - elsif event.commented?
+ = render "events/event/note", event: event
+ - else
+ = render "events/event/common", event: event
diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml
index ee1b57278b6..c8662a15adb 100644
--- a/app/views/layouts/notify.html.haml
+++ b/app/views/layouts/notify.html.haml
@@ -33,7 +33,7 @@
= yield
%div.footer{style: "margin-top: 10px;"}
%p
- \—
+ &mdash;
%br
- if @target_url
#{link_to "View it on GitLab", @target_url}
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index 378dfa2dce0..767fe2e0e9a 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -59,22 +59,22 @@
%div
= link_to 'Enable Two-factor Authentication', new_profile_two_factor_auth_path, class: 'btn btn-success'
- - if show_profile_social_tab?
+ - if button_based_providers.any?
.panel.panel-default
.panel-heading
Connected Accounts
.panel-body
.oauth-buttons.append-bottom-10
%p Click on icon to activate signin with one of the following services
- - enabled_social_providers.each do |provider|
+ - button_based_providers.each do |provider|
.btn-group
- = link_to oauth_image_tag(provider), omniauth_authorize_path(User, provider),
- method: :post, class: "btn btn-lg #{'active' if oauth_active?(provider)}"
- - if oauth_active?(provider)
+ = link_to provider_image_tag(provider), user_omniauth_authorize_path(provider), method: :post, class: "btn btn-lg #{'active' if auth_active?(provider)}", "data-no-turbolink" => "true"
+
+ - if auth_active?(provider)
= link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'btn btn-lg' do
= icon('close')
- - if show_profile_username_tab?
+ - if current_user.can_change_username?
.panel.panel-warning.update-username
.panel-heading
Change Username
@@ -94,7 +94,7 @@
%div
= f.submit 'Save username', class: "btn btn-warning"
- - if show_profile_remove_tab?
+ - if signup_enabled?
.panel.panel-danger.remove-account
.panel-heading
Remove account
diff --git a/app/views/profiles/two_factor_auths/new.html.haml b/app/views/profiles/two_factor_auths/new.html.haml
index 74268c9bde2..92dc58c10d7 100644
--- a/app/views/profiles/two_factor_auths/new.html.haml
+++ b/app/views/profiles/two_factor_auths/new.html.haml
@@ -5,7 +5,7 @@
Download the Google Authenticator application from App Store for iOS or Google
Play for Android and scan this code.
- More information is available in the #{link_to('documentation', help_page_path('workflow', 'two_factor_authentication'))}.
+ More information is available in the #{link_to('documentation', help_page_path('profile', 'two_factor_authentication'))}.
%hr
diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml
index 84742608986..f3b01ff3288 100644
--- a/app/views/projects/blob/diff.html.haml
+++ b/app/views/projects/blob/diff.html.haml
@@ -11,7 +11,7 @@
%td.old_line.diff-line-num{data: {linenumber: line_old}}
= link_to raw(line_old), "#"
%td.new_line= link_to raw(line_new) , "#"
- %td.line_content.noteable_line= line
+ %td.line_content.noteable_line= ' ' * @form.indent + line
- if @form.unfold? && @form.bottom? && @form.to < @blob.loc
%tr.line_holder{ id: @form.to }
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index ed4c601bcdb..977ca423f75 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -1,6 +1,7 @@
- too_big = diff_file.diff_lines.count > Commit::DIFF_SAFE_LINES
- if too_big
- %a.supp_diff_link Changes suppressed. Click to show
+ .suppressed-container
+ %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show.
%table.text-file{class: "#{'hide' if too_big}"}
- last_line = 0
diff --git a/app/views/projects/diffs/_warning.html.haml b/app/views/projects/diffs/_warning.html.haml
index da3d4be84ba..caed0e69dc8 100644
--- a/app/views/projects/diffs/_warning.html.haml
+++ b/app/views/projects/diffs/_warning.html.haml
@@ -3,7 +3,7 @@
Too many changes to show.
.pull-right
- unless diff_hard_limit_enabled?
- = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true)), class: "btn btn-sm btn-warning"
+ = link_to "Reload with full diff", url_for(params.merge(force_show_diff: true, format: :html)), class: "btn btn-sm btn-warning"
- if current_controller?(:commit) or current_controller?(:merge_requests)
- if current_controller?(:commit)
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 1b45bb1af0c..b6910c8f796 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -3,43 +3,42 @@
.issue-check
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue"
- = cache issue do
- .issue-title
- %span.issue-title-text
- = link_to_gfm issue.title, issue_path(issue), class: "row_title"
- .issue-labels
- - issue.labels.each do |label|
- = link_to_label(label, project: issue.project)
- .pull-right.light
- - if issue.closed?
- %span
- CLOSED
- - if issue.assignee
- = link_to_member(@project, issue.assignee, name: false)
- - note_count = issue.notes.user.count
- - if note_count > 0
- &nbsp;
- %span
- %i.fa.fa-comments
- = note_count
- - else
- &nbsp;
- %span.issue-no-comments
- %i.fa.fa-comments
- = 0
-
- .issue-info
- = "#{issue.to_reference} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
- - if issue.votes_count > 0
- = render 'votes/votes_inline', votable: issue
- - if issue.milestone
+ .issue-title
+ %span.issue-title-text
+ = link_to_gfm issue.title, issue_path(issue), class: "row_title"
+ .issue-labels
+ - issue.labels.each do |label|
+ = link_to_label(label, project: issue.project)
+ .pull-right.light
+ - if issue.closed?
+ %span
+ CLOSED
+ - if issue.assignee
+ = link_to_member(@project, issue.assignee, name: false)
+ - note_count = issue.notes.user.count
+ - if note_count > 0
&nbsp;
%span
- %i.fa.fa-clock-o
- = issue.milestone.title
- - if issue.tasks?
- %span.task-status
- = issue.task_status
+ %i.fa.fa-comments
+ = note_count
+ - else
+ &nbsp;
+ %span.issue-no-comments
+ %i.fa.fa-comments
+ = 0
+
+ .issue-info
+ = "#{issue.to_reference} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
+ - if issue.votes_count > 0
+ = render 'votes/votes_inline', votable: issue
+ - if issue.milestone
+ &nbsp;
+ %span
+ %i.fa.fa-clock-o
+ = issue.milestone.title
+ - if issue.tasks?
+ %span.task-status
+ = issue.task_status
- .pull-right.issue-updated-at
- %small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
+ .pull-right.issue-updated-at
+ %small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index faaa85896cf..c57eee14143 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -66,11 +66,9 @@
#notes.notes.tab-pane.voting_notes
= render "projects/merge_requests/discussion"
#commits.commits.tab-pane
- - if current_page?(action: 'commits')
- = render "projects/merge_requests/show/commits"
+ - # This tab is always loaded via AJAX
#diffs.diffs.tab-pane
- - if current_page?(action: 'diffs')
- = render "projects/merge_requests/show/diffs"
+ - # This tab is always loaded via AJAX
.mr-loading-status
= spinner
diff --git a/app/views/projects/notes/_edit_form.html.haml b/app/views/projects/notes/_edit_form.html.haml
index 7472b33bb53..8f7d2e84c70 100644
--- a/app/views/projects/notes/_edit_form.html.haml
+++ b/app/views/projects/notes/_edit_form.html.haml
@@ -3,10 +3,7 @@
= note_target_fields(note)
= render layout: 'projects/md_preview', locals: { preview_class: 'note-text' } do
= render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text js-task-list-field'
-
- .comment-hints.clearfix
- .pull-left #{link_to 'Markdown ', help_page_path('markdown', 'markdown'),{ target: '_blank', tabindex: -1 }}
- .pull-right #{link_to 'Attach a file', '#', class: 'markdown-selector', tabindex: -1 }
+ = render 'projects/notes/hints'
.note-form-actions
.buttons
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index 64f98741d45..3be8f44b282 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -8,18 +8,8 @@
= f.hidden_field :noteable_type
= render layout: 'projects/md_preview', locals: { preview_class: "note-text", referenced_users: true } do
- = render 'projects/zen', f: f, attr: :note,
- classes: 'note_text js-note-text'
-
- .comment-hints.clearfix
- .pull-left
- = link_to "Markdown ", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }
- tip:
- = random_markdown_tip
- .pull-right
- = link_to '#', class: 'markdown-selector', tabindex: -1 do
- Attach a file
- = icon('paperclip')
+ = render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text'
+ = render 'projects/notes/hints'
.error-alert
.note-form-actions
diff --git a/app/views/projects/notes/_hints.html.haml b/app/views/projects/notes/_hints.html.haml
new file mode 100644
index 00000000000..6e7929bdab0
--- /dev/null
+++ b/app/views/projects/notes/_hints.html.haml
@@ -0,0 +1,9 @@
+.comment-hints.clearfix
+ .pull-left
+ = link_to 'Markdown', help_page_path('markdown', 'markdown'), target: '_blank', tabindex: -1
+ tip:
+ = random_markdown_tip
+ .pull-right
+ = link_to '#', class: 'markdown-selector', tabindex: -1 do
+ = icon('paperclip')
+ Attach a file
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index c8d705687da..4a1009686c6 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -56,10 +56,9 @@
.note-body{class: note_editable?(note) ? 'js-task-list-container' : ''}
- = cache [note, 'markdown', user_color_scheme_class] do
- .note-text
- = preserve do
- = markdown(note.note, {no_header_anchors: true})
+ .note-text
+ = preserve do
+ = markdown(note.note, {no_header_anchors: true})
= render 'projects/notes/edit_form', note: note
- if note.attachment.url
diff --git a/app/views/projects/refs/logs_tree.js.haml b/app/views/projects/refs/logs_tree.js.haml
index 35c15cf3a9e..db7f244d002 100644
--- a/app/views/projects/refs/logs_tree.js.haml
+++ b/app/views/projects/refs/logs_tree.js.haml
@@ -11,9 +11,11 @@
- if @logs.present?
:plain
var current_url = location.href.replace(/\/?$/, '/');
- var log_url = '#{namespace_project_tree_url(@project.namespace, @project, tree_join(@ref, @path || '/'))}'.replace(/\/?$/, '/');
+ var log_url = "#{escape_javascript(@log_url)}".replace(/\/?$/, '/');
+
if(current_url == log_url) {
- // Load 10 more commit log for each file in tree
+ // Load more commit logs for each file in tree
// if we still on the same page
- ajaxGet('#{logs_file_namespace_project_ref_path(@project.namespace, @project, @ref, @path || '', offset: (@offset + @limit))}');
+ var url = "#{escape_javascript(@more_log_url)}";
+ ajaxGet(url);
}
diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree.html.haml
index d304690d162..5048154cb2f 100644
--- a/app/views/projects/tree/_tree.html.haml
+++ b/app/views/projects/tree/_tree.html.haml
@@ -49,5 +49,5 @@
:javascript
// Load last commit log for each file in tree
$('#tree-slider').waitForImages(function() {
- ajaxGet('#{@logs_path}');
+ ajaxGet("#{escape_javascript(@logs_path)}");
});
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index 83cd4c66672..5c4dd7f91ae 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -3,6 +3,10 @@
%h3.page-title
= @page.title
= render 'main_links'
+
+.wiki-last-edit-by
+ Last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
+
- if @page.historical?
.warning_message
This is an old version of this page.
@@ -16,6 +20,6 @@
= render_wiki_content(@page)
%hr
-
.wiki-last-edit-by
Last edited by #{@page.commit.author.name} #{time_ago_with_tooltip(@page.commit.authored_date)}
+
diff --git a/app/views/shared/issuable/_context.html.haml b/app/views/shared/issuable/_context.html.haml
index d1bd5ef968d..19e8c31975b 100644
--- a/app/views/shared/issuable/_context.html.haml
+++ b/app/views/shared/issuable/_context.html.haml
@@ -8,7 +8,7 @@
- else
none
.issuable-context-selectbox
- - if can?(current_user, :"admin_#{issuable.class.to_s.underscore}", @project)
+ - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
= users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true)
%div.prepend-top-20.clearfix
@@ -24,7 +24,7 @@
- else
none
.issuable-context-selectbox
- - if can?(current_user, :"admin_#{issuable.class.to_s.underscore}", @project)
+ - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
= f.select(:milestone_id, milestone_options(issuable), { include_blank: 'Select milestone' }, {class: 'select2 select2-compact js-select2 js-milestone'})
= hidden_field_tag :issuable_context
= f.submit class: 'btn hide'
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index e434e1b6b98..8cc0b517cd2 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -38,7 +38,7 @@
.clearfix
.error-alert
%hr
-- if can?(current_user, :admin_issue, @project)
+- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.form-group
.issue-assignee
= f.label :assignee_id, class: 'control-label' do
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 6dc0d170826..56770335ddc 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -209,20 +209,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', app_id: 'YOUR_APP_ID',
+ # - { 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', app_id: 'YOUR_APP_ID',
+ # - { 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',
# args: { scope: 'user:email' } }
- # - { name: 'gitlab', app_id: 'YOUR_APP_ID',
+ # - { 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: 'saml',
+ # - { name: 'bitbucket',
+ # app_id: 'YOUR_APP_ID',
+ # app_secret: 'YOUR_APP_SECRET' }
+ # - { name: 'saml',
+ # label: 'Our SAML Provider',
# args: {
# assertion_consumer_service_url: 'https://gitlab.example.com/users/auth/saml/callback',
# idp_cert_fingerprint: '43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8',
diff --git a/db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb b/db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb
index ffa22e6d5ef..61ff0af41f4 100644
--- a/db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb
+++ b/db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb
@@ -1,5 +1,7 @@
class AddSessionExpireDelayForApplicationSettings < ActiveRecord::Migration
def change
- add_column :application_settings, :session_expire_delay, :integer, default: 10080, null: false
+ unless column_exists?(:application_settings, :session_expire_delay)
+ add_column :application_settings, :session_expire_delay, :integer, default: 10080, null: false
+ end
end
-end \ No newline at end of file
+end
diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md
index d6272cd5912..538894f5848 100644
--- a/doc/gitlab-basics/README.md
+++ b/doc/gitlab-basics/README.md
@@ -2,7 +2,7 @@
Step-by-step guides on the basics of working with Git and GitLab.
-* [Start using Git on the commandline](start-using-git.md)
+* [Start using Git on the command line](start-using-git.md)
* [Create and add your SSH Keys](create-your-ssh-keys.md)
@@ -17,3 +17,5 @@ Step-by-step guides on the basics of working with Git and GitLab.
* [Create a branch](create-branch.md)
* [Fork a project](fork-project.md)
+
+* [Add a file](add-file.md)
diff --git a/doc/gitlab-basics/add-file.md b/doc/gitlab-basics/add-file.md
new file mode 100644
index 00000000000..e7c441e7698
--- /dev/null
+++ b/doc/gitlab-basics/add-file.md
@@ -0,0 +1,31 @@
+# How to add a file
+
+You can create a file in your [shell](command-line-commands.md) or in GitLab.
+
+To create a file in GitLab, sign in to [GitLab.com](https://gitlab.com).
+
+Select a project on the right side of your screen:
+
+![Select a project](basicsimages/select_project.png)
+
+It's a good idea to [create a branch](create-branch.md), but it's not necessary.
+
+Go to the directory where you'd like to add the file and click on the "+" sign next to the name of the project and directory:
+
+![Create a file](basicsimages/create_file.png)
+
+Name your file (you can't add spaces, so you can use hyphens or underscores). Don't forget to include the markup language you'd like to use :
+
+![File name](basicsimages/file_name.png)
+
+Add all the information that you'd like to include in your file:
+
+![Add information](basicsimages/white_space.png)
+
+Add a commit message based on what you just added and then click on "commit changes":
+
+![Commit changes](basicsimages/commit_changes.png)
+
+### Note
+Besides its regular files, every directory needs a README.md or README.html file which works like an index, telling
+what the directory is about. It's the first document you'll find when you open a directory.
diff --git a/doc/integration/gitlab_actions.png b/doc/integration/gitlab_actions.png
deleted file mode 100644
index b08f54d137b..00000000000
--- a/doc/integration/gitlab_actions.png
+++ /dev/null
Binary files differ
diff --git a/doc/integration/gitlab_buttons_in_gmail.md b/doc/integration/gitlab_buttons_in_gmail.md
deleted file mode 100644
index e35bb8ba693..00000000000
--- a/doc/integration/gitlab_buttons_in_gmail.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# GitLab buttons in Gmail
-
-GitLab supports [Google actions in email](https://developers.google.com/gmail/markup/actions/actions-overview).
-
-If correctly setup, emails that require an action will be marked in Gmail.
-
-![gitlab_actions](gitlab_actions.png)
-
-To get this functioning, you need to be registered with Google.
-[See how to register with Google in this document.](https://developers.google.com/gmail/markup/registering-with-google)
-
-To aid the registering with Google, GitLab offers a rake task that will send an email to Google whitelisting email address from your GitLab server.
-
-To check what would be sent to the Google email address, run the rake task:
-
-```bash
-bundle exec rake gitlab:mail_google_schema_whitelisting RAILS_ENV=production
-```
-
-**This will not send the email but give you the output of how the mail will look.**
-
-Copy the output of the rake task to [Google email markup tester](https://www.google.com/webmasters/markup-tester/u/0/) and press "Validate".
-
-If you receive "No errors detected" message from the tester you can send the email using:
-
-```bash
-bundle exec rake gitlab:mail_google_schema_whitelisting RAILS_ENV=production SEND=true
-```
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 8e2a602ec35..2010cb9b8a1 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -84,7 +84,7 @@ Existing users can enable OmniAuth for specific providers after the account is c
1. Sign in normally - whether standard sign in, LDAP, or another OmniAuth provider.
1. Go to profile settings (the silhouette icon in the top right corner).
1. Select the "Account" tab.
-1. Under "Social Accounts" select the desired OmniAuth provider, such as Twitter.
+1. Under "Connected Accounts" select the desired OmniAuth provider, such as Twitter.
1. The user will be redirected to the provider. Once the user authorized GitLab they will be redirected back to GitLab.
The chosen OmniAuth provider is now active and can be used to sign in to GitLab from then on.
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index 70b7e17795d..e81432c600f 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -17,6 +17,7 @@ If a user is a GitLab administrator they receive all permissions.
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
+| Manage merge requests | | | ✓ | ✓ | ✓ |
| Create new merge request | | | ✓ | ✓ | ✓ |
| Create new branches | | | ✓ | ✓ | ✓ |
| Push to non-protected branches | | | ✓ | ✓ | ✓ |
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index ca9696e957e..552b24195b1 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -68,7 +68,7 @@ Xth: (2 working days before the 22nd)
Xth: (1 working day before the 22nd)
- [ ] Merge CE stable into EE stable
-- [ ] Create (hopefully final) CE, EE, CI release candidates (#LINK)
+- [ ] Create CE, EE, CI release candidates (#LINK) (hopefully final ones with the same commit as the release tomorrow)
- [ ] Create Omnibus tags and build packages for the latest release candidates
- [ ] Update GitLab.com with the latest RC (#LINK)
- [ ] Update ci.gitLab.com with the latest RC (#LINK)
@@ -81,10 +81,10 @@ workday to quickly fix any issues.
- [ ] Merge CE stable into EE stable (#LINK)
- [ ] Create the 'x.y.0' tag with the [release tools](https://dev.gitlab.org/gitlab/release-tools) (#LINK)
-- [ ] BEFORE 11AM CET Create and push omnibus tags for x.y.0 (will auto-release the packages) (#LINK)
-- [ ] BEFORE 12AM CET Publish the release blog post (#LINK)
+- [ ] Try to do before 11AM CET: Create and push omnibus tags for x.y.0 (will auto-release the packages) (#LINK)
+- [ ] Try to do before 12AM CET: Publish the release blog post (#LINK)
- [ ] Tweet about the release (blog post) (#LINK)
-- [ ] Schedule a second tweet of the release announcement at 6PM CET / 9AM PST
+- [ ] Schedule a second tweet of the release announcement with the same text at 6PM CET / 9AM PST
```
@@ -220,4 +220,4 @@ Consider creating a post on Hacker News.
## Create a WIP blogpost for the next release
-Create a WIP blogpost using [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md).
+Create a WIP blogpost using [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md). \ No newline at end of file
diff --git a/doc/workflow/importing/README.md b/doc/workflow/importing/README.md
index 19395657719..cd98d1b9852 100644
--- a/doc/workflow/importing/README.md
+++ b/doc/workflow/importing/README.md
@@ -6,4 +6,7 @@
4. [SVN](migrating_from_svn.md)
### Note
-* If you'd like to migrate from a self-hosted GitLab instance to GitLab.com, you can copy your repos by changing the remote and pushing to the new server; but issues and merge requests can't be imported. \ No newline at end of file
+* If you'd like to migrate from a self-hosted GitLab instance to GitLab.com, you can copy your repos by changing the remote and pushing to the new server; but issues and merge requests can't be imported.
+
+* Repositories are imported to GitLab via HTTP.
+If the repository is too large, it can timeout. We have a soft limit of 10GB.
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index af68cb96ed9..d3a77466a35 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -158,3 +158,10 @@ Feature: Project Source Browse Files
Given I visit project source page for "6d394385cf567f80a8fd85055db1ab4c5295806f"
And I click on ".gitignore" file in repo
Then I don't see the permalink link
+
+ @javascript
+ Scenario: I browse code with single quotes in the ref
+ Given I switch ref to 'test'
+ And I see the ref 'test' has been selected
+ And I visit the 'test' tree
+ Then I see the commit data
diff --git a/features/steps/admin/users.rb b/features/steps/admin/users.rb
index 6c4b91586d6..49e64eeff71 100644
--- a/features/steps/admin/users.rb
+++ b/features/steps/admin/users.rb
@@ -3,6 +3,14 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps
include SharedPaths
include SharedAdmin
+ before do
+ allow(Devise).to receive(:omniauth_providers).and_return([:twitter, :twitter_updated])
+ end
+
+ after do
+ allow(Devise).to receive(:omniauth_providers).and_call_original
+ end
+
step 'I should see all users' do
User.all.each do |user|
expect(page).to have_content user.name
@@ -121,7 +129,6 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps
end
step 'I visit "Pete" identities page in admin' do
- allow(Gitlab::OAuth::Provider).to receive(:names).and_return(%w(twitter twitter_updated))
visit admin_user_identities_path(@user)
end
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 95879b9544d..5cb085db207 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -193,6 +193,23 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
FileUtils.rm_f(File.join(@project.repository.path, 'hooks', 'pre-receive'))
end
+ step "I switch ref to 'test'" do
+ select "'test'", from: 'ref'
+ end
+
+ step "I see the ref 'test' has been selected" do
+ expect(page).to have_selector '.select2-chosen', text: "'test'"
+ end
+
+ step "I visit the 'test' tree" do
+ visit namespace_project_tree_path(@project.namespace, @project, "'test'")
+ end
+
+ step 'I see the commit data' do
+ expect(page).to have_css('.tree-commit-link', visible: true)
+ expect(page).not_to have_content('Loading commit data...')
+ end
+
private
def set_new_content
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index aa43e1dffd9..ce21c699e8f 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -229,7 +229,7 @@ module API
authorize! :read_merge_request, merge_request
- present paginate(merge_request.notes), with: Entities::MRNote
+ present paginate(merge_request.notes.fresh), with: Entities::MRNote
end
# Post comment to merge request
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 03cef30c97d..12292f614e9 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -26,7 +26,12 @@ module Grack
auth!
if project && authorized_request?
- @app.call(env)
+ if ENV['GITLAB_GRACK_AUTH_ONLY'] == '1'
+ # Tell gitlab-git-http-server the request is OK, and what the GL_ID is
+ render_grack_auth_ok
+ else
+ @app.call(env)
+ end
elsif @user.nil? && !@gitlab_ci
unauthorized
else
@@ -174,6 +179,10 @@ module Grack
end
end
+ def render_grack_auth_ok
+ [200, { "Content-Type" => "application/json" }, [JSON.dump({ 'GL_ID' => Gitlab::ShellEnv.gl_id(@user) })]]
+ end
+
def render_not_found
[404, { "Content-Type" => "text/plain" }, ["Not Found"]]
end
diff --git a/lib/gitlab/backend/shell_env.rb b/lib/gitlab/backend/shell_env.rb
index 17ec029eed4..9f5adee594a 100644
--- a/lib/gitlab/backend/shell_env.rb
+++ b/lib/gitlab/backend/shell_env.rb
@@ -7,7 +7,7 @@ module Gitlab
def set_env(user)
# Set GL_ID env variable
if user
- ENV['GL_ID'] = "user-#{user.id}"
+ ENV['GL_ID'] = gl_id(user)
end
end
@@ -15,5 +15,14 @@ module Gitlab
# Reset GL_ID env variable
ENV['GL_ID'] = nil
end
+
+ def gl_id(user)
+ if user.present?
+ "user-#{user.id}"
+ else
+ # This empty string is used in the render_grack_auth_ok method
+ ""
+ end
+ end
end
end
diff --git a/lib/gitlab/bitbucket_import/client.rb b/lib/gitlab/bitbucket_import/client.rb
index 5b1952b9675..778b76f6890 100644
--- a/lib/gitlab/bitbucket_import/client.rb
+++ b/lib/gitlab/bitbucket_import/client.rb
@@ -1,6 +1,8 @@
module Gitlab
module BitbucketImport
class Client
+ class Unauthorized < StandardError; end
+
attr_reader :consumer, :api
def initialize(access_token = nil, access_token_secret = nil)
@@ -46,23 +48,23 @@ module Gitlab
end
def user
- JSON.parse(api.get("/api/1.0/user").body)
+ JSON.parse(get("/api/1.0/user").body)
end
def issues(project_identifier)
- JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/issues").body)
+ JSON.parse(get("/api/1.0/repositories/#{project_identifier}/issues").body)
end
def issue_comments(project_identifier, issue_id)
- JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/issues/#{issue_id}/comments").body)
+ JSON.parse(get("/api/1.0/repositories/#{project_identifier}/issues/#{issue_id}/comments").body)
end
def project(project_identifier)
- JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}").body)
+ JSON.parse(get("/api/1.0/repositories/#{project_identifier}").body)
end
def find_deploy_key(project_identifier, key)
- JSON.parse(api.get("/api/1.0/repositories/#{project_identifier}/deploy-keys").body).find do |deploy_key|
+ JSON.parse(get("/api/1.0/repositories/#{project_identifier}/deploy-keys").body).find do |deploy_key|
deploy_key["key"].chomp == key.chomp
end
end
@@ -82,11 +84,18 @@ module Gitlab
end
def projects
- JSON.parse(api.get("/api/1.0/user/repositories").body).select { |repo| repo["scm"] == "git" }
+ JSON.parse(get("/api/1.0/user/repositories").body).select { |repo| repo["scm"] == "git" }
end
private
+ def get(url)
+ response = api.get(url)
+ raise Unauthorized if (400..499).include?(response.code.to_i)
+
+ response
+ end
+
def config
Gitlab.config.omniauth.providers.find { |provider| provider.name == "bitbucket"}
end
diff --git a/lib/gitlab/o_auth/provider.rb b/lib/gitlab/o_auth/provider.rb
index f986499a27c..90c3fe8da33 100644
--- a/lib/gitlab/o_auth/provider.rb
+++ b/lib/gitlab/o_auth/provider.rb
@@ -1,18 +1,30 @@
module Gitlab
module OAuth
class Provider
- def self.names
- providers = []
+ def self.providers
+ Devise.omniauth_providers
+ end
- Gitlab.config.ldap.servers.values.each do |server|
- providers << server['provider_name']
- end
+ def self.enabled?(name)
+ providers.include?(name.to_sym)
+ end
- Gitlab.config.omniauth.providers.each do |provider|
- providers << provider['name']
+ def self.ldap_provider?(name)
+ name.to_s.start_with?('ldap')
+ end
+
+ def self.config_for(name)
+ name = name.to_s
+ if ldap_provider?(name)
+ Gitlab::LDAP::Config.new(name).options
+ else
+ Gitlab.config.omniauth.providers.find { |provider| provider.name == name }
end
+ end
- providers
+ def self.label_for(name)
+ config = config_for(name)
+ (config && config['label']) || name.to_s.titleize
end
end
end
diff --git a/lib/gitlab/satellite/merge_action.rb b/lib/gitlab/satellite/merge_action.rb
index 1f2e5f82dd5..f9bf286697e 100644
--- a/lib/gitlab/satellite/merge_action.rb
+++ b/lib/gitlab/satellite/merge_action.rb
@@ -33,7 +33,7 @@ module Gitlab
merge_repo.git.push(default_options, :origin, merge_request.target_branch)
# remove source branch
- if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch) && !merge_request.for_fork?
+ if merge_request.remove_source_branch?
# will raise CommandFailed when push fails
merge_repo.git.push(default_options, :origin, ":#{merge_request.source_branch}")
end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index 2f7aff03c2a..04440e4f68d 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -22,10 +22,10 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
ERB::Util.html_escape_once(text)
end
- # Stolen from Rugments::Plugins::Redcarpet as this module is not required
- # from Rugments's gem root.
+ # Stolen from Rouge::Plugins::Redcarpet as this module is not required
+ # from Rouge's gem root.
def block_code(code, language)
- lexer = Rugments::Lexer.find_fancy(language, code) || Rugments::Lexers::PlainText
+ lexer = Rouge::Lexer.find_fancy(language, code) || Rouge::Lexers::PlainText
# XXX HACK: Redcarpet strips hard tabs out of code blocks,
# so we assume you're not using leading spaces that aren't tabs,
@@ -34,7 +34,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
code.gsub!(/^ /, "\t")
end
- formatter = Rugments::Formatters::HTML.new(
+ formatter = Rouge::Formatters::HTMLGitlab.new(
cssclass: "code highlight #{@color_scheme} #{lexer.tag}"
)
formatter.format(lexer.lex(code))
diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb
new file mode 100644
index 00000000000..485af6832d7
--- /dev/null
+++ b/lib/rouge/formatters/html_gitlab.rb
@@ -0,0 +1,168 @@
+require 'cgi'
+
+module Rouge
+ module Formatters
+ class HTMLGitlab < Rouge::Formatter
+ tag 'html_gitlab'
+
+ # Creates a new <tt>Rouge::Formatter::HTMLGitlab</tt> instance.
+ #
+ # [+nowrap+] If set to True, don't wrap the output at all, not
+ # even inside a <tt><pre></tt> tag (default: false).
+ # [+cssclass+] CSS class for the wrapping <tt><div></tt> tag
+ # (default: 'highlight').
+ # [+linenos+] If set to 'table', output line numbers as a table
+ # with two cells, one containing the line numbers,
+ # the other the whole code. This is copy paste friendly,
+ # but may cause alignment problems with some browsers
+ # or fonts. If set to 'inline', the line numbers will
+ # be integrated in the <tt><pre></tt> tag that contains
+ # the code (default: nil).
+ # [+linenostart+] The line number for the first line (default: 1).
+ # [+lineanchors+] If set to true the formatter will wrap each output
+ # line in an anchor tag with a name of L-linenumber.
+ # This allows easy linking to certain lines
+ # (default: false).
+ # [+lineanchorsid+] If lineanchors is true the name of the anchors can
+ # be changed with lineanchorsid to e.g. foo-linenumber
+ # (default: 'L').
+ # [+anchorlinenos+] If set to true, will wrap line numbers in <tt><a></tt>
+ # tags. Used in combination with linenos and lineanchors
+ # (default: false).
+ # [+inline_theme+] Inline CSS styles for the <pre> tag (default: false).
+ def initialize(
+ nowrap: false,
+ cssclass: 'highlight',
+ linenos: nil,
+ linenostart: 1,
+ lineanchors: false,
+ lineanchorsid: 'L',
+ anchorlinenos: false,
+ inline_theme: nil
+ )
+ @nowrap = nowrap
+ @cssclass = cssclass
+ @linenos = linenos
+ @linenostart = linenostart
+ @lineanchors = lineanchors
+ @lineanchorsid = lineanchorsid
+ @anchorlinenos = anchorlinenos
+ @inline_theme = Theme.find(@inline_theme).new if @inline_theme.is_a?(String)
+ end
+
+ def render(tokens)
+ case @linenos
+ when 'table'
+ render_tableized(tokens)
+ when 'inline'
+ render_untableized(tokens)
+ else
+ render_untableized(tokens)
+ end
+ end
+
+ alias_method :format, :render
+
+ private
+
+ def render_untableized(tokens)
+ data = process_tokens(tokens)
+
+ html = ''
+ html << "<pre class=\"#{@cssclass}\"><code>" unless @nowrap
+ html << wrap_lines(data[:code])
+ html << "</code></pre>\n" unless @nowrap
+ html
+ end
+
+ def render_tableized(tokens)
+ data = process_tokens(tokens)
+
+ html = ''
+ html << "<div class=\"#{@cssclass}\">" unless @nowrap
+ html << '<table><tbody>'
+ html << "<td class=\"linenos\"><pre>"
+ html << wrap_linenos(data[:numbers])
+ html << '</pre></td>'
+ html << "<td class=\"lines\"><pre><code>"
+ html << wrap_lines(data[:code])
+ html << '</code></pre></td>'
+ html << '</tbody></table>'
+ html << '</div>' unless @nowrap
+ html
+ end
+
+ def process_tokens(tokens)
+ num_lines = 0
+ last_val = ''
+ rendered = ''
+
+ tokens.each do |tok, val|
+ last_val = val
+ num_lines += val.scan(/\n/).size
+ rendered << span(tok, val)
+ end
+
+ numbers = (@linenostart..num_lines + @linenostart - 1).to_a
+
+ { numbers: numbers, code: rendered }
+ end
+
+ def wrap_linenos(numbers)
+ if @anchorlinenos
+ numbers.map! do |number|
+ "<a href=\"##{@lineanchorsid}#{number}\">#{number}</a>"
+ end
+ end
+ numbers.join("\n")
+ end
+
+ def wrap_lines(rendered)
+ if @lineanchors
+ lines = rendered.split("\n")
+ lines = lines.each_with_index.map do |line, index|
+ number = index + @linenostart
+
+ if @linenos == 'inline'
+ "<a name=\"L#{number}\"></a>" \
+ "<span class=\"linenos\">#{number}</span>" \
+ "<span id=\"#{@lineanchorsid}#{number}\" class=\"line\">#{line}" \
+ '</span>'
+ else
+ "<span id=\"#{@lineanchorsid}#{number}\" class=\"line\">#{line}" \
+ '</span>'
+ end
+ end
+ lines.join("\n")
+ else
+ if @linenos == 'inline'
+ lines = rendered.split("\n")
+ lines = lines.each_with_index.map do |line, index|
+ number = index + @linenostart
+ "<span class=\"linenos\">#{number}</span>#{line}"
+ end
+ lines.join("\n")
+ else
+ rendered
+ end
+ end
+ end
+
+ def span(tok, val)
+ # http://stackoverflow.com/a/1600584/2587286
+ val = CGI.escapeHTML(val)
+
+ if tok.shortname.empty?
+ val
+ else
+ if @inline_theme
+ rules = @inline_theme.style_for(tok).rendered_rules
+ "<span style=\"#{rules.to_a.join(';')}\">#{val}</span>"
+ else
+ "<span class=\"#{tok.shortname}\">#{val}</span>"
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index edb987875df..efa0898900f 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -38,6 +38,11 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
+## Experimental: gitlab-git-http-server
+# upstream gitlab-git-http-server {
+# server localhost:8181;
+# }
+
## Normal HTTP host
server {
## Either remove "default_server" from the listen line below,
@@ -109,6 +114,26 @@ server {
proxy_pass http://gitlab;
}
+ ## Experimental: send Git HTTP traffic to gitlab-git-http-server instead of Unicorn
+ # location ~ [-\/\w\.]+\.git\/ {
+ # ## If you use HTTPS make sure you disable gzip compression
+ # ## to be safe against BREACH attack.
+ # # gzip off;
+
+ # ## https://github.com/gitlabhq/gitlabhq/issues/694
+ # ## Some requests take more than 30 seconds.
+ # proxy_read_timeout 300;
+ # proxy_connect_timeout 300;
+ # proxy_redirect off;
+
+ # proxy_set_header Host $http_host;
+ # proxy_set_header X-Real-IP $remote_addr;
+ # 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;
+ # }
+
## Enable gzip compression as per rails guide:
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
## WARNING: If you are using relative urls remove the block below
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 766559b49f6..314525518f1 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -42,6 +42,11 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
}
+## Experimental: gitlab-git-http-server
+# upstream gitlab-git-http-server {
+# server localhost:8181;
+# }
+
## Redirects all HTTP traffic to the HTTPS host
server {
## Either remove "default_server" from the listen line below,
@@ -156,6 +161,26 @@ server {
proxy_pass http://gitlab;
}
+ ## Experimental: send Git HTTP traffic to gitlab-git-http-server instead of Unicorn
+ # location ~ [-\/\w\.]+\.git\/ {
+ # ## If you use HTTPS make sure you disable gzip compression
+ # ## to be safe against BREACH attack.
+ # gzip off;
+
+ # ## https://github.com/gitlabhq/gitlabhq/issues/694
+ # ## Some requests take more than 30 seconds.
+ # proxy_read_timeout 300;
+ # proxy_connect_timeout 300;
+ # proxy_redirect off;
+
+ # proxy_set_header Host $http_host;
+ # proxy_set_header X-Real-IP $remote_addr;
+ # 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;
+ # }
+
## Enable gzip compression as per rails guide:
## http://guides.rubyonrails.org/asset_pipeline.html#gzip-compression
## WARNING: If you are using relative urls remove the block below
diff --git a/lib/tasks/gitlab/mail_google_schema_whitelisting.rake b/lib/tasks/gitlab/mail_google_schema_whitelisting.rake
deleted file mode 100644
index 102c6ae55d5..00000000000
--- a/lib/tasks/gitlab/mail_google_schema_whitelisting.rake
+++ /dev/null
@@ -1,73 +0,0 @@
-require "#{Rails.root}/app/helpers/emails_helper"
-require 'action_view/helpers'
-extend ActionView::Helpers
-
-include ActionView::Context
-include EmailsHelper
-
-namespace :gitlab do
- desc "Email google whitelisting email with example email for actions in inbox"
- task mail_google_schema_whitelisting: :environment do
- subject = "Rails | Implemented feature"
- url = "#{Gitlab.config.gitlab.url}/base/rails-project/issues/#{rand(1..100)}#note_#{rand(10..1000)}"
- schema = email_action(url)
- body = email_template(schema, url)
- mail = Notify.test_email("schema.whitelisting+sample@gmail.com", subject, body.html_safe)
- if send_now
- mail.deliver
- else
- puts "WOULD SEND:"
- end
- puts mail
- end
-
- def email_template(schema, url)
- "<html lang='en'>
- <head>
- <meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
- <title>
- GitLab
- </title>
- </meta>
- </head>
- <style>
- img {
- max-width: 100%;
- height: auto;
- }
- p.details {
- font-style:italic;
- color:#777
- }
- .footer p {
- font-size:small;
- color:#777
- }
- </style>
- <body>
- <div class='content'>
- <div>
- <p>I like it :+1: </p>
- </div>
- </div>
-
- <div class='footer' style='margin-top: 10px;'>
- <p>
- <br>
- <a href=\"#{url}\">View it on GitLab</a>
- You're receiving this notification because you are a member of the Base / Rails Project project team.
- #{schema}
- </p>
- </div>
- </body>
- </html>"
- end
-
- def send_now
- if ENV['SEND'] == "true"
- true
- else
- false
- end
- end
-end
diff --git a/lib/tasks/gitlab/update_commit_count.rake b/lib/tasks/gitlab/update_commit_count.rake
new file mode 100644
index 00000000000..9b636f12d9f
--- /dev/null
+++ b/lib/tasks/gitlab/update_commit_count.rake
@@ -0,0 +1,20 @@
+namespace :gitlab do
+ desc "GitLab | Update commit count for projects"
+ task update_commit_count: :environment do
+ projects = Project.where(commit_count: 0)
+ puts "#{projects.size} projects need to be updated. This might take a while."
+ ask_to_continue unless ENV['force'] == 'yes'
+
+ projects.find_each(batch_size: 100) do |project|
+ print "#{project.name_with_namespace.yellow} ... "
+
+ unless project.repo_exists?
+ puts "skipping, because the repo is empty".magenta
+ next
+ end
+
+ project.update_commit_count
+ puts project.commit_count.to_s.green
+ end
+ end
+end
diff --git a/lib/unfold_form.rb b/lib/unfold_form.rb
index 46b12beeaaf..fcd01503d1b 100644
--- a/lib/unfold_form.rb
+++ b/lib/unfold_form.rb
@@ -8,4 +8,5 @@ class UnfoldForm
attribute :bottom, Boolean
attribute :unfold, Boolean, default: true
attribute :offset, Integer
+ attribute :indent, Integer, default: 0
end
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index d47a37914df..9f89101d7f7 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -1,25 +1,38 @@
require 'spec_helper'
describe UsersController do
- let(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') }
-
- before do
- sign_in(user)
- end
+ let(:user) { create(:user) }
describe 'GET #show' do
- render_views
+ it 'is case-insensitive' do
+ user = create(:user, username: 'CamelCaseUser')
+ sign_in(user)
+
+ get :show, username: user.username.downcase
- it 'renders the show template' do
- get :show, username: user.username
- expect(response.status).to eq(200)
- expect(response).to render_template('show')
+ expect(response).to be_success
+ end
+
+ context 'with rendered views' do
+ render_views
+
+ it 'renders the show template' do
+ sign_in(user)
+
+ get :show, username: user.username
+
+ expect(response).to be_success
+ expect(response).to render_template('show')
+ end
end
end
describe 'GET #calendar' do
it 'renders calendar' do
+ sign_in(user)
+
get :calendar, username: user.username
+
expect(response).to render_template('calendar')
end
end
@@ -30,6 +43,8 @@ describe UsersController do
before do
allow_any_instance_of(User).to receive(:contributed_projects_ids).and_return([project.id])
+
+ sign_in(user)
project.team << [user, :developer]
end
diff --git a/spec/features/admin/security_spec.rb b/spec/features/security/admin_access_spec.rb
index 175fa9d4647..fe8cd7b7602 100644
--- a/spec/features/admin/security_spec.rb
+++ b/spec/features/security/admin_access_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe "Admin::Projects", feature: true do
+ include AccessMatchers
+
describe "GET /admin/projects" do
subject { admin_namespaces_projects_path }
diff --git a/spec/features/security/dashboard_access_spec.rb b/spec/features/security/dashboard_access_spec.rb
index 67238e3ab76..c38cddbb904 100644
--- a/spec/features/security/dashboard_access_spec.rb
+++ b/spec/features/security/dashboard_access_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe "Dashboard access", feature: true do
+ include AccessMatchers
+
describe "GET /dashboard" do
subject { dashboard_path }
diff --git a/spec/features/security/group/group_access_spec.rb b/spec/features/security/group/group_access_spec.rb
deleted file mode 100644
index 63793149459..00000000000
--- a/spec/features/security/group/group_access_spec.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-require 'spec_helper'
-
-describe "Group access", feature: true do
- describe "GET /projects/new" do
- it { expect(new_group_path).to be_allowed_for :admin }
- it { expect(new_group_path).to be_allowed_for :user }
- it { expect(new_group_path).to be_denied_for :visitor }
- end
-
- describe "Group" do
- let(:group) { create(:group) }
-
- let(:owner) { create(:owner) }
- let(:master) { create(:user) }
- let(:reporter) { create(:user) }
- let(:guest) { create(:user) }
- let(:nonmember) { create(:user) }
-
- before do
- group.add_user(owner, Gitlab::Access::OWNER)
- group.add_user(master, Gitlab::Access::MASTER)
- group.add_user(reporter, Gitlab::Access::REPORTER)
- group.add_user(guest, Gitlab::Access::GUEST)
- end
-
- describe "GET /groups/:path" do
- subject { group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/issues" do
- subject { issues_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/merge_requests" do
- subject { merge_requests_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/group_members" do
- subject { group_group_members_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/edit" do
- subject { edit_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_denied_for master }
- it { is_expected.to be_denied_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_denied_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/projects" do
- subject { projects_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_denied_for master }
- it { is_expected.to be_denied_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_denied_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
- end
-end
diff --git a/spec/features/security/group/internal_group_access_spec.rb b/spec/features/security/group/internal_group_access_spec.rb
deleted file mode 100644
index d17a7412e43..00000000000
--- a/spec/features/security/group/internal_group_access_spec.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-require 'spec_helper'
-
-describe "Group with internal project access", feature: true do
- describe "Group" do
- let(:group) { create(:group) }
-
- let(:owner) { create(:owner) }
- let(:master) { create(:user) }
- let(:reporter) { create(:user) }
- let(:guest) { create(:user) }
- let(:nonmember) { create(:user) }
-
- before do
- group.add_user(owner, Gitlab::Access::OWNER)
- group.add_user(master, Gitlab::Access::MASTER)
- group.add_user(reporter, Gitlab::Access::REPORTER)
- group.add_user(guest, Gitlab::Access::GUEST)
-
- create(:project, :internal, group: group)
- end
-
- describe "GET /groups/:path" do
- subject { group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/issues" do
- subject { issues_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/merge_requests" do
- subject { merge_requests_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/group_members" do
- subject { group_group_members_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
-
- describe "GET /groups/:path/edit" do
- subject { edit_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_denied_for master }
- it { is_expected.to be_denied_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_denied_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
- end
-end
diff --git a/spec/features/security/group/mixed_group_access_spec.rb b/spec/features/security/group/mixed_group_access_spec.rb
deleted file mode 100644
index b3db7b5dea4..00000000000
--- a/spec/features/security/group/mixed_group_access_spec.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-require 'spec_helper'
-
-describe "Group access", feature: true do
- describe "Group" do
- let(:group) { create(:group) }
-
- let(:owner) { create(:owner) }
- let(:master) { create(:user) }
- let(:reporter) { create(:user) }
- let(:guest) { create(:user) }
- let(:nonmember) { create(:user) }
-
- before do
- group.add_user(owner, Gitlab::Access::OWNER)
- group.add_user(master, Gitlab::Access::MASTER)
- group.add_user(reporter, Gitlab::Access::REPORTER)
- group.add_user(guest, Gitlab::Access::GUEST)
-
- create(:project, :internal, path: "internal_project", group: group)
- create(:project, :public, path: "public_project", group: group)
- end
-
- describe "GET /groups/:path" do
- subject { group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_allowed_for :visitor }
- end
-
- describe "GET /groups/:path/issues" do
- subject { issues_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_allowed_for :visitor }
- end
-
- describe "GET /groups/:path/merge_requests" do
- subject { merge_requests_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_allowed_for :visitor }
- end
-
- describe "GET /groups/:path/group_members" do
- subject { group_group_members_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_allowed_for :visitor }
- end
-
- describe "GET /groups/:path/edit" do
- subject { edit_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_denied_for master }
- it { is_expected.to be_denied_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_denied_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
- end
-end
diff --git a/spec/features/security/group/public_group_access_spec.rb b/spec/features/security/group/public_group_access_spec.rb
deleted file mode 100644
index c16f0c0d1e1..00000000000
--- a/spec/features/security/group/public_group_access_spec.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-require 'spec_helper'
-
-describe "Group with public project access", feature: true do
- describe "Group" do
- let(:group) { create(:group) }
-
- let(:owner) { create(:owner) }
- let(:master) { create(:user) }
- let(:reporter) { create(:user) }
- let(:guest) { create(:user) }
- let(:nonmember) { create(:user) }
-
- before do
- group.add_user(owner, Gitlab::Access::OWNER)
- group.add_user(master, Gitlab::Access::MASTER)
- group.add_user(reporter, Gitlab::Access::REPORTER)
- group.add_user(guest, Gitlab::Access::GUEST)
-
- create(:project, :public, group: group)
- end
-
- describe "GET /groups/:path" do
- subject { group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_allowed_for :visitor }
- end
-
- describe "GET /groups/:path/issues" do
- subject { issues_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_allowed_for :visitor }
- end
-
- describe "GET /groups/:path/merge_requests" do
- subject { merge_requests_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_allowed_for :visitor }
- end
-
- describe "GET /groups/:path/group_members" do
- subject { group_group_members_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_allowed_for master }
- it { is_expected.to be_allowed_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_allowed_for guest }
- it { is_expected.to be_allowed_for :user }
- it { is_expected.to be_allowed_for :visitor }
- end
-
- describe "GET /groups/:path/edit" do
- subject { edit_group_path(group) }
-
- it { is_expected.to be_allowed_for owner }
- it { is_expected.to be_denied_for master }
- it { is_expected.to be_denied_for reporter }
- it { is_expected.to be_allowed_for :admin }
- it { is_expected.to be_denied_for guest }
- it { is_expected.to be_denied_for :user }
- it { is_expected.to be_denied_for :visitor }
- end
- end
-end
diff --git a/spec/features/security/group_access_spec.rb b/spec/features/security/group_access_spec.rb
new file mode 100644
index 00000000000..8ce15388605
--- /dev/null
+++ b/spec/features/security/group_access_spec.rb
@@ -0,0 +1,284 @@
+require 'rails_helper'
+
+describe 'Group access', feature: true do
+ include AccessMatchers
+
+ def group
+ @group ||= create(:group)
+ end
+
+ def create_project(access_level)
+ if access_level == :mixed
+ create(:empty_project, :public, group: group)
+ create(:empty_project, :internal, group: group)
+ else
+ create(:empty_project, access_level, group: group)
+ end
+ end
+
+ def group_member(access_level, group = group)
+ level = Object.const_get("Gitlab::Access::#{access_level.upcase}")
+
+ create(:user).tap do |user|
+ group.add_user(user, level)
+ end
+ end
+
+ describe 'GET /groups/new' do
+ subject { new_group_path }
+
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
+ describe 'GET /groups/:path' do
+ subject { group_path(group) }
+
+ context 'with public projects' do
+ let!(:project) { create_project(:public) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context 'with mixed projects' do
+ let!(:project) { create_project(:mixed) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context 'with internal projects' do
+ let!(:project) { create_project(:internal) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
+ context 'with no projects' do
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+ end
+
+ describe 'GET /groups/:path/issues' do
+ subject { issues_group_path(group) }
+
+ context 'with public projects' do
+ let!(:project) { create_project(:public) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context 'with mixed projects' do
+ let!(:project) { create_project(:mixed) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context 'with internal projects' do
+ let!(:project) { create_project(:internal) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
+ context 'with no projects' do
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+ end
+
+ describe 'GET /groups/:path/merge_requests' do
+ subject { merge_requests_group_path(group) }
+
+ context 'with public projects' do
+ let!(:project) { create_project(:public) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context 'with mixed projects' do
+ let!(:project) { create_project(:mixed) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context 'with internal projects' do
+ let!(:project) { create_project(:internal) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
+ context 'with no projects' do
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+ end
+
+ describe 'GET /groups/:path/group_members' do
+ subject { group_group_members_path(group) }
+
+ context 'with public projects' do
+ let!(:project) { create_project(:public) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context 'with mixed projects' do
+ let!(:project) { create_project(:mixed) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_allowed_for :visitor }
+ end
+
+ context 'with internal projects' do
+ let!(:project) { create_project(:internal) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_allowed_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
+ context 'with no projects' do
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_allowed_for group_member(:master) }
+ it { is_expected.to be_allowed_for group_member(:reporter) }
+ it { is_expected.to be_allowed_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+ end
+
+ describe 'GET /groups/:path/edit' do
+ subject { edit_group_path(group) }
+
+ context 'with public projects' do
+ let!(:project) { create_project(:public) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_denied_for group_member(:master) }
+ it { is_expected.to be_denied_for group_member(:reporter) }
+ it { is_expected.to be_denied_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
+ context 'with mixed projects' do
+ let!(:project) { create_project(:mixed) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_denied_for group_member(:master) }
+ it { is_expected.to be_denied_for group_member(:reporter) }
+ it { is_expected.to be_denied_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
+ context 'with internal projects' do
+ let!(:project) { create_project(:internal) }
+
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_denied_for group_member(:master) }
+ it { is_expected.to be_denied_for group_member(:reporter) }
+ it { is_expected.to be_denied_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
+ context 'with no projects' do
+ it { is_expected.to be_allowed_for group_member(:owner) }
+ it { is_expected.to be_denied_for group_member(:master) }
+ it { is_expected.to be_denied_for group_member(:reporter) }
+ it { is_expected.to be_denied_for group_member(:guest) }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+ end
+end
diff --git a/spec/features/security/profile_access_spec.rb b/spec/features/security/profile_access_spec.rb
index bcabc2d53ac..c19678ab381 100644
--- a/spec/features/security/profile_access_spec.rb
+++ b/spec/features/security/profile_access_spec.rb
@@ -1,18 +1,11 @@
require 'spec_helper'
describe "Profile access", feature: true do
- before do
- @u1 = create(:user)
- end
-
- describe "GET /login" do
- it { expect(new_user_session_path).not_to be_not_found_for :visitor }
- end
+ include AccessMatchers
describe "GET /profile/keys" do
subject { profile_keys_path }
- it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
@@ -21,7 +14,6 @@ describe "Profile access", feature: true do
describe "GET /profile" do
subject { profile_path }
- it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
@@ -30,7 +22,6 @@ describe "Profile access", feature: true do
describe "GET /profile/account" do
subject { profile_account_path }
- it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
@@ -39,7 +30,6 @@ describe "Profile access", feature: true do
describe "GET /profile/preferences" do
subject { profile_preferences_path }
- it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
@@ -48,7 +38,6 @@ describe "Profile access", feature: true do
describe "GET /profile/audit_log" do
subject { audit_log_profile_path }
- it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
@@ -57,7 +46,6 @@ describe "Profile access", feature: true do
describe "GET /profile/notifications" do
subject { profile_notifications_path }
- it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 4649e58cb1a..57563add74c 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe "Internal Project Access", feature: true do
+ include AccessMatchers
+
let(:project) { create(:project, :internal) }
let(:master) { create(:user) }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index 2866bf0355b..a1e111c6cab 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe "Private Project Access", feature: true do
+ include AccessMatchers
+
let(:project) { create(:project) }
let(:master) { create(:user) }
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 554c96bcdc5..655d2c8b7d9 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe "Public Project Access", feature: true do
+ include AccessMatchers
+
let(:project) { create(:project) }
let(:master) { create(:user) }
@@ -17,7 +19,6 @@ describe "Public Project Access", feature: true do
# readonly
project.team << [reporter, :reporter]
-
end
describe "Project should be public" do
diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb
new file mode 100644
index 00000000000..e47a54fdac5
--- /dev/null
+++ b/spec/helpers/auth_helper_spec.rb
@@ -0,0 +1,20 @@
+require "spec_helper"
+
+describe AuthHelper do
+ describe "button_based_providers" do
+ it 'returns all enabled providers' do
+ allow(helper).to receive(:auth_providers) { [:twitter, :github] }
+ expect(helper.button_based_providers).to include(*[:twitter, :github])
+ end
+
+ it 'does not return ldap provider' do
+ allow(helper).to receive(:auth_providers) { [:twitter, :ldapmain] }
+ expect(helper.button_based_providers).to include(:twitter)
+ end
+
+ it 'returns empty array' do
+ allow(helper).to receive(:auth_providers) { [] }
+ expect(helper.button_based_providers).to eq([])
+ end
+ end
+end
diff --git a/spec/helpers/oauth_helper_spec.rb b/spec/helpers/oauth_helper_spec.rb
deleted file mode 100644
index 3ef35f35102..00000000000
--- a/spec/helpers/oauth_helper_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require "spec_helper"
-
-describe OauthHelper do
- describe "additional_providers" do
- it 'returns all enabled providers' do
- allow(helper).to receive(:enabled_oauth_providers) { [:twitter, :github] }
- expect(helper.additional_providers).to include(*[:twitter, :github])
- end
-
- it 'does not return ldap provider' do
- allow(helper).to receive(:enabled_oauth_providers) { [:twitter, :ldapmain] }
- expect(helper.additional_providers).to include(:twitter)
- end
-
- it 'returns empty array' do
- allow(helper).to receive(:enabled_oauth_providers) { [] }
- expect(helper.additional_providers).to eq([])
- end
- end
-end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index beb9b4e438e..99abb95d906 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -22,7 +22,7 @@ describe ProjectsHelper do
let(:user) { create(:user) }
- it "returns false if there are no approipriate permissions" do
+ it "returns false if there are no appropriate permissions" do
allow(helper).to receive(:can?) { false }
expect(helper.can_change_visibility_level?(project, user)).to be_falsey
@@ -52,4 +52,22 @@ describe ProjectsHelper do
end
end
end
+
+ describe "readme_cache_key" do
+ let(:project) { create(:project) }
+
+ before do
+ helper.instance_variable_set(:@project, project)
+ end
+
+ it "returns a valid cach key" do
+ expect(helper.send(:readme_cache_key)).to eq("#{project.id}-#{project.commit.id}-readme")
+ end
+
+ it "returns a valid cache key if HEAD does not exist" do
+ allow(project).to receive(:commit) { nil }
+
+ expect(helper.send(:readme_cache_key)).to eq("#{project.id}-nil-readme")
+ end
+ end
end
diff --git a/spec/javascripts/merge_request_tabs_spec.js.coffee b/spec/javascripts/merge_request_tabs_spec.js.coffee
index 6cc96fb68a0..a0cfba455ea 100644
--- a/spec/javascripts/merge_request_tabs_spec.js.coffee
+++ b/spec/javascripts/merge_request_tabs_spec.js.coffee
@@ -51,6 +51,12 @@ describe 'MergeRequestTabs', ->
expect(@subject('notes')).toBe('/foo/bar/merge_requests/1')
expect(@subject('commits')).toBe('/foo/bar/merge_requests/1/commits')
+ it 'changes from diffs.html', ->
+ @class._location = stubLocation(pathname: '/foo/bar/merge_requests/1/diffs.html')
+
+ expect(@subject('notes')).toBe('/foo/bar/merge_requests/1')
+ expect(@subject('commits')).toBe('/foo/bar/merge_requests/1/commits')
+
it 'changes from notes', ->
@class._location = stubLocation(pathname: '/foo/bar/merge_requests/1')
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 16902317f10..76f16323e2f 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -442,6 +442,18 @@ describe User do
end
end
+ describe '.find_by_username!' do
+ it 'raises RecordNotFound' do
+ expect { described_class.find_by_username!('JohnDoe') }.
+ to raise_error(ActiveRecord::RecordNotFound)
+ end
+
+ it 'is case-insensitive' do
+ user = create(:user, username: 'JohnDoe')
+ expect(described_class.find_by_username!('JOHNDOE')).to eq user
+ end
+ end
+
describe 'all_ssh_keys' do
it { is_expected.to have_many(:keys).dependent(:destroy) }
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 7030c105b58..29db035b2de 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -8,6 +8,7 @@ describe API::API, api: true do
let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test") }
let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test") }
let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
+ let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") }
before do
project.team << [user, :reporters]
@@ -397,13 +398,14 @@ describe API::API, api: true do
end
describe "GET :id/merge_request/:merge_request_id/comments" do
- it "should return merge_request comments" do
+ it "should return merge_request comments ordered by created_at" do
get api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
- expect(json_response.length).to eq(1)
+ expect(json_response.length).to eq(2)
expect(json_response.first['note']).to eq("a comment on a MR")
expect(json_response.first['author']['id']).to eq(user.id)
+ expect(json_response.last['note']).to eq("another comment on a MR")
end
it "should return a 404 error if merge_request_id not found" do
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 97b206c9854..66cdfd5d758 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -4,13 +4,19 @@ describe Projects::CreateService do
describe :create_by_user do
before do
@user = create :user
- @admin = create :user, admin: true
@opts = {
name: "GitLab",
namespace: @user.namespace
}
end
+ it 'creates services on Project creation' do
+ project = create_project(@user, @opts)
+ project.reload
+
+ expect(project.services).not_to be_empty
+ end
+
context 'user namespace' do
before do
@project = create_project(@user, @opts)
@@ -75,7 +81,9 @@ describe Projects::CreateService do
end
it 'should allow a restricted visibility level for admins' do
- project = create_project(@admin, @opts)
+ admin = create(:admin)
+ project = create_project(admin, @opts)
+
expect(project.errors.any?).to be(false)
expect(project.saved?).to be(true)
end
diff --git a/spec/support/matchers.rb b/spec/support/matchers.rb
deleted file mode 100644
index a2f853e3e70..00000000000
--- a/spec/support/matchers.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-RSpec::Matchers.define :be_valid_commit do
- match do |actual|
- actual &&
- actual.id == ValidCommit::ID &&
- actual.message == ValidCommit::MESSAGE &&
- actual.author_name == ValidCommit::AUTHOR_FULL_NAME
- end
-end
-
-def emulate_user(user)
- user = case user
- when :user then create(:user)
- when :visitor then nil
- when :admin then create(:admin)
- else user
- end
- login_with(user) if user
-end
-
-RSpec::Matchers.define :be_allowed_for do |user|
- match do |url|
- emulate_user(user)
- visit url
- status_code != 404 && current_path != new_user_session_path
- end
-end
-
-RSpec::Matchers.define :be_denied_for do |user|
- match do |url|
- emulate_user(user)
- visit url
- status_code == 404 || current_path == new_user_session_path
- end
-end
-
-RSpec::Matchers.define :be_not_found_for do |user|
- match do |url|
- emulate_user(user)
- visit url
- status_code == 404
- end
-end
-
-RSpec::Matchers.define :include_module do |expected|
- match do
- described_class.included_modules.include?(expected)
- end
-
- description do
- "includes the #{expected} module"
- end
-
- failure_message do
- "expected #{described_class} to include the #{expected} module"
- end
-end
-
-# Extend shoulda-matchers
-module Shoulda::Matchers::ActiveModel
- class ValidateLengthOfMatcher
- # Shortcut for is_at_least and is_at_most
- def is_within(range)
- is_at_least(range.min) && is_at_most(range.max)
- end
- end
-end
diff --git a/spec/support/matchers/access_matchers.rb b/spec/support/matchers/access_matchers.rb
new file mode 100644
index 00000000000..558e8b1612f
--- /dev/null
+++ b/spec/support/matchers/access_matchers.rb
@@ -0,0 +1,54 @@
+# AccessMatchers
+#
+# The custom matchers contained in this module are used to test a user's access
+# to a URL by emulating a specific user or type of user account, visiting the
+# URL, and then checking the response status code and resulting path.
+module AccessMatchers
+ extend RSpec::Matchers::DSL
+ include Warden::Test::Helpers
+
+ def emulate_user(user)
+ case user
+ when :user
+ login_as(create(:user))
+ when :visitor
+ logout
+ when :admin
+ login_as(create(:admin))
+ when User
+ login_as(user)
+ else
+ raise ArgumentError, "cannot emulate user #{user}"
+ end
+ end
+
+ def description_for(user, type)
+ if user.kind_of?(User)
+ # User#inspect displays too much information for RSpec's description
+ # messages
+ "be #{type} for supplied User"
+ else
+ "be #{type} for #{user}"
+ end
+ end
+
+ matcher :be_allowed_for do |user|
+ match do |url|
+ emulate_user(user)
+ visit url
+ status_code != 404 && current_path != new_user_session_path
+ end
+
+ description { description_for(user, 'allowed') }
+ end
+
+ matcher :be_denied_for do |user|
+ match do |url|
+ emulate_user(user)
+ visit url
+ status_code == 404 || current_path == new_user_session_path
+ end
+
+ description { description_for(user, 'denied') }
+ end
+end
diff --git a/spec/support/matchers/include_module.rb b/spec/support/matchers/include_module.rb
new file mode 100644
index 00000000000..0a78af1e90e
--- /dev/null
+++ b/spec/support/matchers/include_module.rb
@@ -0,0 +1,13 @@
+RSpec::Matchers.define :include_module do |expected|
+ match do
+ described_class.included_modules.include?(expected)
+ end
+
+ description do
+ "includes the #{expected} module"
+ end
+
+ failure_message do
+ "expected #{described_class} to include the #{expected} module"
+ end
+end
diff --git a/spec/support/matchers/is_within.rb b/spec/support/matchers/is_within.rb
new file mode 100644
index 00000000000..0c35fc7e899
--- /dev/null
+++ b/spec/support/matchers/is_within.rb
@@ -0,0 +1,9 @@
+# Extend shoulda-matchers
+module Shoulda::Matchers::ActiveModel
+ class ValidateLengthOfMatcher
+ # Shortcut for is_at_least and is_at_most
+ def is_within(range)
+ is_at_least(range.min) && is_at_most(range.max)
+ end
+ end
+end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index ae0b95ea444..8dc687c3580 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -12,7 +12,8 @@ module TestEnv
'fix' => '12d65c8',
'improve/awesome' => '5937ac0',
'markdown' => '0ed8c6c',
- 'master' => '5937ac0'
+ 'master' => '5937ac0',
+ "'test'" => 'e56497b',
}
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily