summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG9
-rw-r--r--CONTRIBUTING.md1
-rw-r--r--Gemfile.lock6
-rw-r--r--README.md2
-rw-r--r--VERSION2
-rw-r--r--app/assets/stylesheets/sections/issues.scss2
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss12
-rw-r--r--app/controllers/admin/users_controller.rb1
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb48
-rw-r--r--app/controllers/projects/blob_controller.rb2
-rw-r--r--app/controllers/projects/edit_tree_controller.rb2
-rw-r--r--app/controllers/sessions_controller.rb4
-rw-r--r--app/finders/snippets_finder.rb22
-rw-r--r--app/helpers/commits_helper.rb4
-rw-r--r--app/helpers/events_helper.rb5
-rw-r--r--app/helpers/gitlab_markdown_helper.rb62
-rw-r--r--app/helpers/oauth_helper.rb2
-rw-r--r--app/models/commit.rb20
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/merge_request_diff.rb2
-rw-r--r--app/models/repository.rb2
-rw-r--r--app/models/user.rb15
-rw-r--r--app/services/files/base_service.rb6
-rw-r--r--app/views/admin/users/index.html.haml20
-rw-r--r--app/views/dashboard/_zero_authorized_projects.html.haml2
-rw-r--r--app/views/devise/sessions/_new_ldap.html.haml2
-rw-r--r--app/views/devise/sessions/new.html.haml17
-rw-r--r--app/views/events/_commit.html.haml2
-rw-r--r--app/views/events/_event_push.atom.haml2
-rw-r--r--app/views/events/event/_push.html.haml2
-rw-r--r--app/views/explore/projects/_project.html.haml1
-rw-r--r--app/views/explore/projects/starred.html.haml2
-rw-r--r--app/views/profiles/notifications/show.html.haml12
-rw-r--r--app/views/projects/_commit_button.html.haml9
-rw-r--r--app/views/projects/blame/show.html.haml2
-rw-r--r--app/views/projects/commit/_commit_box.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/commits/_inline_commit.html.haml2
-rw-r--r--app/views/projects/edit_tree/show.html.haml15
-rw-r--r--app/views/projects/import.html.haml3
-rw-r--r--app/views/projects/merge_requests/_show.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_mr_accept.html.haml17
-rw-r--r--app/views/projects/merge_requests/show/_state_widget.html.haml6
-rw-r--r--app/views/projects/new.html.haml3
-rw-r--r--app/views/projects/new_tree/show.html.haml11
-rw-r--r--app/views/projects/notes/discussions/_diff.html.haml2
-rw-r--r--app/views/projects/protected_branches/index.html.haml6
-rw-r--r--app/views/projects/tree/_submodule_item.html.haml4
-rw-r--r--app/views/projects/wikis/history.html.haml2
-rw-r--r--app/views/search/results/_note.html.haml2
-rw-r--r--config/gitlab.yml.example107
-rw-r--r--config/initializers/1_settings.rb20
-rw-r--r--config/initializers/7_omniauth.rb12
-rw-r--r--config/initializers/devise.rb32
-rw-r--r--db/fixtures/development/12_snippets.rb34
-rw-r--r--doc/README.md1
-rw-r--r--doc/customization/libravatar.md69
-rw-r--r--doc/development/ci_setup.md28
-rw-r--r--doc/install/installation.md12
-rw-r--r--doc/markdown/markdown.md4
-rw-r--r--doc/update/4.2-to-5.0.md6
-rw-r--r--doc/update/6.x-or-7.x-to-7.4.md (renamed from doc/update/6.x-or-7.x-to-7.3.md)23
-rw-r--r--doc/update/7.2-to-7.3.md3
-rw-r--r--doc/update/7.3-to-7.4.md217
-rw-r--r--doc/workflow/README.md2
-rw-r--r--doc/workflow/gitlab_flow.md2
-rw-r--r--doc/workflow/migrating_from_svn.md17
-rw-r--r--doc/workflow/notifications.md71
-rw-r--r--doc/workflow/notifications/settings.pngbin0 -> 114727 bytes
-rw-r--r--features/project/source/browse_files.feature24
-rw-r--r--features/steps/project/commits/commits.rb2
-rw-r--r--features/steps/project/merge_requests.rb2
-rw-r--r--features/steps/project/source/browse_files.rb12
-rw-r--r--features/steps/shared/paths.rb9
-rw-r--r--lib/api/files.rb6
-rw-r--r--lib/gitlab/auth.rb14
-rw-r--r--lib/gitlab/ldap/access.rb36
-rw-r--r--lib/gitlab/ldap/adapter.rb63
-rw-r--r--lib/gitlab/ldap/authentication.rb71
-rw-r--r--lib/gitlab/ldap/config.rb115
-rw-r--r--lib/gitlab/ldap/person.rb26
-rw-r--r--lib/gitlab/ldap/user.rb93
-rw-r--r--lib/gitlab/markdown.rb18
-rw-r--r--lib/gitlab/oauth/auth_hash.rb2
-rw-r--r--lib/gitlab/oauth/user.rb94
-rw-r--r--lib/redcarpet/render/gitlab_html.rb12
-rw-r--r--lib/support/nginx/gitlab-ssl3
-rw-r--r--spec/factories.rb5
-rw-r--r--spec/helpers/events_helper_spec.rb52
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb34
-rw-r--r--spec/lib/gitlab/auth_spec.rb7
-rw-r--r--spec/lib/gitlab/ldap/access_spec.rb26
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb2
-rw-r--r--spec/lib/gitlab/ldap/authentication_spec.rb53
-rw-r--r--spec/lib/gitlab/ldap/config_spec.rb20
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb40
-rw-r--r--spec/lib/gitlab/oauth/auth_hash_spec.rb55
-rw-r--r--spec/lib/gitlab/oauth/user_spec.rb131
-rw-r--r--spec/models/commit_spec.rb2
-rw-r--r--spec/models/note_spec.rb4
-rw-r--r--spec/models/user_spec.rb47
-rw-r--r--spec/support/mentionable_shared_examples.rb11
102 files changed, 1608 insertions, 528 deletions
diff --git a/CHANGELOG b/CHANGELOG
index c98d21f9865..05290698320 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -26,6 +26,15 @@ v 7.4.0
- Show build coverage in Merge Requests (requires GitLab CI v5.1)
- New milestone and label links on issue edit form
- Improved repository graphs
+ - Improve event note display in dashboard and project activity views (Vinnie Okada)
+ - Add users sorting to admin area
+ - UI improvements
+ - Fix ambiguous sha problem with mentioned commit
+ - Fixed bug with apostrophe when at mentioning users
+ - Add active directory ldap option
+ - Developers can push to wiki repo. Protected branches does not affect wiki repo any more
+ - Faster rev list
+ - Fix branch removal
v 7.3.2
- Fix creating new file via web editor
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ed49080d57a..ce454a11a08 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -92,6 +92,7 @@ For examples of feedback on merge requests please look at already [closed merge
1. The change is as small as possible (see the above paragraph for details)
1. Include proper tests and make all tests pass (unless it contains a test exposing a bug in existing code)
+1. All tests have to pass, if you suspect a failing CI build is unrelated to your contribution ask for tests to be restarted. See [the CI setup document](http://doc.gitlab.com/ce/development/ci_setup.html) on who you can ask for test restart.
1. Initially contains a single commit (please use `git rebase -i` to squash commits)
1. Can merge without problems (if not please merge `master`, never rebase commits pushed to the remote server)
1. Does not break any existing functionality
diff --git a/Gemfile.lock b/Gemfile.lock
index 1de2911fb15..0e82f14ca9d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -241,9 +241,11 @@ GEM
html-pipeline (1.11.0)
activesupport (>= 2)
nokogiri (~> 1.4)
- html-pipeline-gitlab (0.1.0)
- gitlab_emoji (~> 0.0.1.1)
+ html-pipeline-gitlab (0.1.5)
+ actionpack (~> 4)
+ gitlab_emoji (~> 0.0.1)
html-pipeline (~> 1.11.0)
+ sanitize (~> 2.1)
http_parser.rb (0.5.3)
httparty (0.13.0)
json (~> 1.8)
diff --git a/README.md b/README.md
index c0461543f2a..2c0643cf598 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
## Installation
Please see [the installation page on the GitLab website](https://about.gitlab.com/installation/) for the various options.
-Since a manual installation is a lot of work and error prone we strongly recommend fast and reliable Omnibus package installation (deb/rpm) on that page.
+Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
## Third-party applications
diff --git a/VERSION b/VERSION
index 8b258729874..7b65f139cb2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.4.0-pre
+7.4.0.rc1
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index a7fa715d2e0..ebf8a6125c7 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -75,7 +75,7 @@
}
.participants {
- margin-bottom: 10px;
+ margin-bottom: 20px;
}
.issues_bulk_update {
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index c8d0cac2926..ec844cc00b0 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -111,31 +111,38 @@
.ci_widget {
padding: 10px 15px;
font-size: 15px;
- border-bottom: 1px dashed #AAA;
+ border-bottom: 1px solid #BBB;
+ color: #777;
+ background-color: #F5F5F5;
&.ci-success {
color: $bg_success;
border-color: $border_success;
+ background-color: #F1FAF1;
}
&.ci-pending {
color: #548;
border-color: #548;
+ background-color: #F4F1FA;
}
&.ci-running {
color: $bg_warning;
border-color: $border_warning;
+ background-color: #FAF5F1;
}
&.ci-failed {
color: $bg_danger;
border-color: $border_danger;
+ background-color: #FAF1F1;
}
&.ci-error {
color: $bg_danger;
border-color: $border_danger;
+ background-color: #FAF1F1;
}
}
@@ -143,7 +150,8 @@
padding: 10px 15px;
h4 {
- margin-top: 0px;
+ font-size: 20px;
+ font-weight: normal;
}
p:last-child {
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index f63df27eebd..baad9095b70 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -4,6 +4,7 @@ class Admin::UsersController < Admin::ApplicationController
def index
@users = User.filter(params[:filter])
@users = @users.search(params[:name]) if params[:name].present?
+ @users = @users.sort(@sort = params[:sort])
@users = @users.alphabetically.page(params[:page])
end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 3ed6a69c2d8..bd4b310fcbf 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -15,15 +15,17 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
error.to_s.humanize if error
end
+ # We only find ourselves here
+ # if the authentication to LDAP was successful.
def ldap
- # We only find ourselves here
- # if the authentication to LDAP was successful.
- @user = Gitlab::LDAP::User.find_or_create(oauth)
- @user.remember_me = true if @user.persisted?
+ @user = Gitlab::LDAP::User.new(oauth)
+ @user.save if @user.changed? # will also save new users
+ gl_user = @user.gl_user
+ gl_user.remember_me = true if @user.persisted?
# Do additional LDAP checks for the user filter and EE features
- if Gitlab::LDAP::Access.allowed?(@user)
- sign_in_and_redirect(@user)
+ if @user.allowed?
+ sign_in_and_redirect(gl_user)
else
flash[:alert] = "Access denied for your LDAP account."
redirect_to new_user_session_path
@@ -46,26 +48,28 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
current_user.save
redirect_to profile_path
else
- @user = Gitlab::OAuth::User.find(oauth)
+ @user = Gitlab::OAuth::User.new(oauth)
+ @user.save
- # Create user if does not exist
- # and allow_single_sign_on is true
- if Gitlab.config.omniauth['allow_single_sign_on'] && !@user
- @user, errors = Gitlab::OAuth::User.create(oauth)
- end
-
- if @user && !errors
- sign_in_and_redirect(@user)
+ # Only allow properly saved users to login.
+ if @user.persisted? && @user.valid?
+ sign_in_and_redirect(@user.gl_user)
else
- if errors
- error_message = errors.map{ |attribute, message| "#{attribute} #{message}" }.join(", ")
- redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
- else
- flash[:notice] = "There's no such user!"
- end
- redirect_to new_user_session_path
+ error_message =
+ if @user.gl_user.errors.any?
+ @user.gl_user.errors.map do |attribute, message|
+ "#{attribute} #{message}"
+ end.join(", ")
+ else
+ ''
+ end
+
+ redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
end
end
+ rescue StandardError
+ flash[:notice] = "There's no such user!"
+ redirect_to new_user_session_path
end
def oauth
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 7009e3b1bc8..0944c7421ee 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -20,7 +20,7 @@ class Projects::BlobController < Projects::ApplicationController
flash[:notice] = "Your changes have been successfully committed"
redirect_to project_tree_path(@project, @ref)
else
- flash[:alert] = result[:error]
+ flash[:alert] = result[:message]
render :show
end
end
diff --git a/app/controllers/projects/edit_tree_controller.rb b/app/controllers/projects/edit_tree_controller.rb
index 8976d7c7be8..fdc1a85d8d7 100644
--- a/app/controllers/projects/edit_tree_controller.rb
+++ b/app/controllers/projects/edit_tree_controller.rb
@@ -22,7 +22,7 @@ class Projects::EditTreeController < Projects::BaseTreeController
redirect_to after_edit_path
else
- flash[:alert] = result[:error]
+ flash[:alert] = result[:message]
render :show
end
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 1bdba75c5e7..5ced98152a5 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -18,6 +18,10 @@ class SessionsController < Devise::SessionsController
store_location_for(:redirect, redirect_path)
end
+ if Gitlab.config.ldap.enabled
+ @ldap_servers = Gitlab::LDAP::Config.servers
+ end
+
super
end
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index fda375aca2f..b29ab6cf40b 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -30,18 +30,18 @@ class SnippetsFinder
snippets = user.snippets.fresh.non_expired
if user == current_user
- snippets = case scope
- when 'are_internal' then
- snippets.are_internal
- when 'are_private' then
- snippets.are_private
- when 'are_public' then
- snippets.are_public
- else
- snippets
- end
+ case scope
+ when 'are_internal' then
+ snippets.are_internal
+ when 'are_private' then
+ snippets.are_private
+ when 'are_public' then
+ snippets.are_public
+ else
+ snippets
+ end
else
- snippets = snippets.public_and_internal
+ snippets.public_and_internal
end
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index cab2984a4c4..0e0532b65b2 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -120,4 +120,8 @@ module CommitsHelper
class: 'commit-short-id')
end
end
+
+ def truncate_sha(sha)
+ Commit.truncate_sha(sha)
+ end
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 6aeab7bb8ce..71f97fbb8c8 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -136,9 +136,8 @@ module EventsHelper
end
def event_note(text)
- text = first_line_in_markdown(text)
- text = truncate(text, length: 150)
- sanitize(markdown(text), tags: %w(a img b pre p))
+ text = first_line_in_markdown(text, 150)
+ sanitize(text, tags: %w(a img b pre code p))
end
def event_commit_title(message)
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 0365681a128..7d3cb749829 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -51,12 +51,14 @@ module GitlabMarkdownHelper
@markdown.render(text).html_safe
end
- def first_line_in_markdown(text)
- line = text.split("\n").detect do |i|
- i.present? && markdown(i).present?
- end
- line += '...' unless line.nil?
- line
+ # Return the first line of +text+, up to +max_chars+, after parsing the line
+ # as Markdown. HTML tags in the parsed output are not counted toward the
+ # +max_chars+ limit. If the length limit falls within a tag's contents, then
+ # the tag contents are truncated without removing the closing tag.
+ def first_line_in_markdown(text, max_chars = nil)
+ md = markdown(text).strip
+
+ truncate_visible(md, max_chars || md.length) if md.present?
end
def render_wiki_content(wiki_page)
@@ -204,4 +206,52 @@ module GitlabMarkdownHelper
def correct_ref
@ref ? @ref : "master"
end
+
+ private
+
+ # Return +text+, truncated to +max_chars+ characters, excluding any HTML
+ # tags.
+ def truncate_visible(text, max_chars)
+ doc = Nokogiri::HTML.fragment(text)
+ content_length = 0
+ truncated = false
+
+ doc.traverse do |node|
+ if node.text? || node.content.empty?
+ if truncated
+ node.remove
+ next
+ end
+
+ # Handle line breaks within a node
+ if node.content.strip.lines.length > 1
+ node.content = "#{node.content.lines.first.chomp}..."
+ truncated = true
+ end
+
+ num_remaining = max_chars - content_length
+ if node.content.length > num_remaining
+ node.content = node.content.truncate(num_remaining)
+ truncated = true
+ end
+ content_length += node.content.length
+ end
+
+ truncated = truncate_if_block(node, truncated)
+ end
+
+ doc.to_html
+ end
+
+ # Used by #truncate_visible. If +node+ is the first block element, and the
+ # text hasn't already been truncated, then append "..." to the node contents
+ # and return true. Otherwise return false.
+ def truncate_if_block(node, truncated)
+ if node.element? && node.description.block? && !truncated
+ node.content = "#{node.content}..." if node.next_sibling
+ true
+ else
+ truncated
+ end
+ end
end
diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb
index c0177dacbf8..7024483b8b3 100644
--- a/app/helpers/oauth_helper.rb
+++ b/app/helpers/oauth_helper.rb
@@ -1,6 +1,6 @@
module OauthHelper
def ldap_enabled?
- Devise.omniauth_providers.include?(:ldap)
+ Gitlab.config.ldap.enabled
end
def default_providers
diff --git a/app/models/commit.rb b/app/models/commit.rb
index a1343b65c72..212229649fc 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -19,13 +19,24 @@ class Commit
class << self
def decorate(commits)
- commits.map { |c| self.new(c) }
+ commits.map do |commit|
+ if commit.kind_of?(Commit)
+ commit
+ else
+ self.new(commit)
+ end
+ end
end
# Calculate number of lines to render for diffs
def diff_line_count(diffs)
diffs.reduce(0) { |sum, d| sum + d.diff.lines.count }
end
+
+ # Truncate sha to 8 characters
+ def truncate_sha(sha)
+ sha[0..7]
+ end
end
attr_accessor :raw
@@ -111,7 +122,7 @@ class Commit
# Mentionable override.
def gfm_reference
- "commit #{sha[0..5]}"
+ "commit #{id}"
end
def method_missing(m, *args, &block)
@@ -124,6 +135,11 @@ class Commit
super
end
+ # Truncate sha to 8 characters
+ def short_id
+ @raw.short_id(7)
+ end
+
def parents
@parents ||= Commit.decorate(super)
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 9e296c00281..c0b126713a6 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -266,7 +266,7 @@ class Event < ActiveRecord::Base
end
def note_short_commit_id
- note_commit_id[0..8]
+ Commit.truncate_sha(note_commit_id)
end
def note_commit?
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 409e82ed1ef..a71122d5e07 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -55,7 +55,7 @@ class MergeRequestDiff < ActiveRecord::Base
end
def last_commit_short_sha
- @last_commit_short_sha ||= last_commit.sha[0..10]
+ @last_commit_short_sha ||= last_commit.short_id
end
private
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 339e485e6d2..93994123a90 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -30,6 +30,8 @@ class Repository
commit = Gitlab::Git::Commit.find(raw_repository, id)
commit = Commit.new(commit) if commit
commit
+ rescue Rugged::OdbError => ex
+ nil
end
def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false)
diff --git a/app/models/user.rb b/app/models/user.rb
index c90f2462426..42faea0070e 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -178,8 +178,7 @@ class User < ActiveRecord::Base
scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
scope :not_in_project, ->(project) { project.users.present? ? where("id not in (:ids)", ids: project.users.map(&:id) ) : all }
scope :without_projects, -> { where('id NOT IN (SELECT DISTINCT(user_id) FROM members)') }
- scope :ldap, -> { where(provider: 'ldap') }
-
+ scope :ldap, -> { where('provider LIKE ?', 'ldap%') }
scope :potential_team_members, ->(team) { team.members.any? ? active.not_in_team(team) : active }
#
@@ -196,6 +195,16 @@ class User < ActiveRecord::Base
end
end
+ def sort(method)
+ case method.to_s
+ when 'recent_sign_in' then reorder('users.last_sign_in_at DESC')
+ when 'oldest_sign_in' then reorder('users.last_sign_in_at ASC')
+ when 'recently_created' then reorder('users.created_at DESC')
+ when 'late_created' then reorder('users.created_at ASC')
+ else reorder("users.name ASC")
+ end
+ end
+
def find_for_commit(email, name)
# Prefer email match over name match
User.where(email: email).first ||
@@ -397,7 +406,7 @@ class User < ActiveRecord::Base
end
def ldap_user?
- extern_uid && provider == 'ldap'
+ extern_uid && provider.start_with?('ldap')
end
def accessible_deploy_keys
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index db6f0831f8b..bd245100955 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -10,12 +10,6 @@ module Files
private
- def success
- out = super()
- out[:error] = ''
- out
- end
-
def repository
project.repository
end
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 5c2664e14fe..92c619738a2 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -32,6 +32,26 @@
.panel-heading
Users (#{@users.total_count})
.panel-head-actions
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %span.light sort:
+ - if @sort.present?
+ = @sort.humanize
+ - else
+ Name
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to admin_users_path(sort: nil) do
+ Name
+ = link_to admin_users_path(sort: 'recent_sign_in') do
+ Recent sign in
+ = link_to admin_users_path(sort: 'oldest_sign_in') do
+ Oldest sign in
+ = link_to admin_users_path(sort: 'recently_created') do
+ Recently created
+ = link_to admin_users_path(sort: 'late_created') do
+ Late created
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
%ul.well-list
- @users.each do |user|
diff --git a/app/views/dashboard/_zero_authorized_projects.html.haml b/app/views/dashboard/_zero_authorized_projects.html.haml
index 711e607f0bc..5d133cd8285 100644
--- a/app/views/dashboard/_zero_authorized_projects.html.haml
+++ b/app/views/dashboard/_zero_authorized_projects.html.haml
@@ -46,5 +46,5 @@
%br
Public projects are an easy way to allow everyone to have read-only access.
.link_holder
- = link_to explore_projects_path, class: "btn btn-new" do
+ = link_to trending_explore_projects_path, class: "btn btn-new" do
Browse public projects »
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index 6c5a878e904..01584611493 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -1,4 +1,4 @@
-= form_tag(user_omniauth_callback_path(:ldap), id: 'new_ldap_user' ) do
+= form_tag(user_omniauth_callback_path(provider), id: 'new_ldap_user' ) do
= text_field_tag :username, nil, {class: "form-control top", placeholder: "LDAP Login", autofocus: "autofocus"}
= password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
%br/
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index b70b0d66172..b9832787446 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -4,20 +4,22 @@
.login-body
- if ldap_enabled? && gitlab_config.signin_enabled
%ul.nav.nav-tabs
- %li.active
- = link_to 'LDAP', '#tab-ldap', 'data-toggle' => 'tab'
+ - @ldap_servers.each_with_index do |server, i|
+ %li{class: (:active if i==0)}
+ = link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab'
%li
= link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab'
.tab-content
- %div#tab-ldap.tab-pane.active
- = render partial: 'devise/sessions/new_ldap'
+ - @ldap_servers.each_with_index do |server,i|
+ %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i==0)}
+ = render 'devise/sessions/new_ldap', provider: server['provider_name']
%div#tab-signin.tab-pane
- = render partial: 'devise/sessions/new_base'
+ = render 'devise/sessions/new_base'
- elsif ldap_enabled?
- = render partial: 'devise/sessions/new_ldap'
+ = render 'devise/sessions/new_ldap', ldap_servers: @ldap_servers
- elsif gitlab_config.signin_enabled
- = render partial: 'devise/sessions/new_base'
+ = render 'devise/sessions/new_base'
- else
%div
No authentication methods configured.
@@ -36,7 +38,6 @@
%span.light Did not receive confirmation email?
= link_to "Send again", new_confirmation_path(resource_name)
-
- if extra_config.has_key?('sign_in_text')
%hr
= markdown(extra_config.sign_in_text)
diff --git a/app/views/events/_commit.html.haml b/app/views/events/_commit.html.haml
index 0e03e116e7d..f0c34def145 100644
--- a/app/views/events/_commit.html.haml
+++ b/app/views/events/_commit.html.haml
@@ -1,5 +1,5 @@
%li.commit
.commit-row-title
- = link_to commit[:id][0..8], project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
+ = link_to truncate_sha(commit[:id]), project_commit_path(project, commit[:id]), class: "commit_short_id", alt: ''
&nbsp;
= gfm event_commit_title(commit[:message]), project
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index 17228c430ca..2b63519edac 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -2,7 +2,7 @@
- event.commits.first(15).each do |commit|
%p
%strong= commit[:author][:name]
- = link_to "(##{commit[:id][0...8]})", project_commit_path(event.project, id: commit[:id])
+ = link_to "(##{truncate_sha(commit[:id])})", project_commit_path(event.project, id: commit[:id])
%i
at
= commit[:timestamp].to_time.to_s(:short)
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index 1bca64c7d50..b912b5e092f 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -22,4 +22,4 @@
- if event.commits_count > 2
%span ... and #{event.commits_count - 2} more commits.
= link_to project_compare_path(event.project, from: event.commit_from, to: event.commit_to) do
- %strong Compare &rarr; #{event.commit_from[0..7]}...#{event.commit_to[0..7]}
+ %strong Compare &rarr; #{truncate_sha(event.commit_from)}...#{truncate_sha(event.commit_to)}
diff --git a/app/views/explore/projects/_project.html.haml b/app/views/explore/projects/_project.html.haml
index 4bc79d0a8c7..ffbddbae4d6 100644
--- a/app/views/explore/projects/_project.html.haml
+++ b/app/views/explore/projects/_project.html.haml
@@ -6,6 +6,7 @@
- if current_page?(starred_explore_projects_path)
%strong.pull-right
+ %i.fa.fa-star
= pluralize project.star_count, 'star'
.project-info
diff --git a/app/views/explore/projects/starred.html.haml b/app/views/explore/projects/starred.html.haml
index d4b11405517..420f0693756 100644
--- a/app/views/explore/projects/starred.html.haml
+++ b/app/views/explore/projects/starred.html.haml
@@ -1,6 +1,6 @@
.explore-trending-block
%p.lead
- %i.fa.fa-comments-o
+ %i.fa.fa-star
See most starred projects
%hr
.public-projects
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index f84de4430cc..a044fad8fa3 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -31,12 +31,12 @@
.clearfix
%hr
- %p
- You can also specify notification level per group or per project
- %br
- By default all projects and groups uses notification level set above
.row.all-notifications
.col-md-6
+ %p
+ You can also specify notification level per group or per project.
+ %br
+ By default all projects and groups uses notification level set above.
%h4 Groups:
%ul.bordered-list
- @group_members.each do |users_group|
@@ -44,6 +44,10 @@
= render 'settings', type: 'group', membership: users_group, notification: notification
.col-md-6
+ %p
+ To specify notification level per project of a group you belong to,
+ %br
+ you need to be a member of the project itself, not only its group.
%h4 Projects:
%ul.bordered-list
- @project_members.each do |project_member|
diff --git a/app/views/projects/_commit_button.html.haml b/app/views/projects/_commit_button.html.haml
new file mode 100644
index 00000000000..fd8320adb8d
--- /dev/null
+++ b/app/views/projects/_commit_button.html.haml
@@ -0,0 +1,9 @@
+.form-actions
+ .commit-button-annotation
+ = button_tag 'Commit Changes',
+ class: 'btn commit-btn js-commit-button btn-create'
+ .message
+ to branch
+ %strong= ref
+ = link_to 'Cancel', cancel_path,
+ class: 'btn btn-cancel', data: {confirm: leave_edit_message}
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index e5cde488c3c..bdf02c6285d 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -15,7 +15,7 @@
%tr
%td.blame-commit
%span.commit
- = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id"
+ = link_to commit.short_id, project_commit_path(@project, commit), class: "commit_short_id"
&nbsp;
= commit_author_link(commit, avatar: true, size: 16)
&nbsp;
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 0b6b6af4f90..e149f017f84 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -35,7 +35,7 @@
.commit-info-row
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
- = link_to parent.id[0...10], project_commit_path(@project, parent)
+ = link_to parent.short_id, project_commit_path(@project, parent)
- if @branches.any?
.commit-info-row
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 68852ba973f..1eb17f760dc 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -1,6 +1,6 @@
%li.commit.js-toggle-container
.commit-row-title
- = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
+ = link_to commit.short_id, project_commit_path(project, commit), class: "commit_short_id"
&nbsp;
%span.str-truncated
= link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
diff --git a/app/views/projects/commits/_inline_commit.html.haml b/app/views/projects/commits/_inline_commit.html.haml
index b36369b4285..574599aa2d2 100644
--- a/app/views/projects/commits/_inline_commit.html.haml
+++ b/app/views/projects/commits/_inline_commit.html.haml
@@ -1,6 +1,6 @@
%li.commit.inline-commit
.commit-row-title
- = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"
+ = link_to commit.short_id, project_commit_path(project, commit), class: "commit_short_id"
&nbsp;
%span.str-truncated
= link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message"
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
index a863f7420a8..5ccde05063e 100644
--- a/app/views/projects/edit_tree/show.html.haml
+++ b/app/views/projects/edit_tree/show.html.haml
@@ -23,16 +23,11 @@
%i.fa.fa-spinner.fa-spin
= render 'shared/commit_message_container', params: params,
placeholder: "Update #{@blob.name}"
- .form-actions
- = hidden_field_tag 'last_commit', @last_commit
- = hidden_field_tag 'content', '', id: "file-content"
- = hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
- .commit-button-annotation
- = button_tag "Commit changes", class: 'btn commit-btn js-commit-button btn-primary'
- .message
- to branch
- %strong= @ref
- = link_to "Cancel", @after_edit_path, class: "btn btn-cancel", data: { confirm: leave_edit_message}
+ = hidden_field_tag 'last_commit', @last_commit
+ = hidden_field_tag 'content', '', id: "file-content"
+ = hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
+ = render 'projects/commit_button', ref: @ref,
+ cancel_path: @after_edit_path
:javascript
ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace")
diff --git a/app/views/projects/import.html.haml b/app/views/projects/import.html.haml
index 1f7fd26c646..4513c89e784 100644
--- a/app/views/projects/import.html.haml
+++ b/app/views/projects/import.html.haml
@@ -19,12 +19,13 @@
= form_for @project, url: retry_import_project_path(@project), method: :put, html: { class: 'form-horizontal' } do |f|
.form-group.import-url-data
= f.label :import_url, class: 'control-label' do
- %span Import existing repo
+ %span Import existing git repo
.col-sm-10
= f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
.bs-callout.bs-callout-info
This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
%br
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
+ For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
.form-actions
= f.submit 'Retry import', class: "btn btn-create", tabindex: 4
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 947e8f58ae5..7b28dd5e7da 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -21,7 +21,7 @@
- content_for :note_actions do
- if can?(current_user, :modify_merge_request, @merge_request)
- - unless @merge_request.closed? || @merge_request.merged?
+ - if @merge_request.open?
= link_to 'Close', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
- if @merge_request.closed?
= link_to 'Reopen', project_merge_request_path(@project, @merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
diff --git a/app/views/projects/merge_requests/show/_mr_accept.html.haml b/app/views/projects/merge_requests/show/_mr_accept.html.haml
index 213e14268c2..4939ae03994 100644
--- a/app/views/projects/merge_requests/show/_mr_accept.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -16,15 +16,6 @@
%h4
You can accept this request automatically.
.accept-merge-holder.clearfix
- .js-toggle-container
- %p
- You can
- %strong= link_to "modify merge commit message", "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message"
- before accepting merge request
- .js-toggle-content.hide
- = render 'shared/commit_message_container', params: params,
- text: @merge_request.merge_commit_message,
- rows: 14, hint: true
.accept-group
.pull-left
= f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
@@ -33,6 +24,14 @@
= label_tag :should_remove_source_branch, class: "checkbox" do
= check_box_tag :should_remove_source_branch
Remove source-branch
+ .js-toggle-container
+ %label
+ %i.fa.fa-edit
+ = link_to "modify merge commit message", "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message"
+ .js-toggle-content.hide
+ = render 'shared/commit_message_container', params: params,
+ text: @merge_request.merge_commit_message,
+ rows: 14, hint: true
%hr
.light
diff --git a/app/views/projects/merge_requests/show/_state_widget.html.haml b/app/views/projects/merge_requests/show/_state_widget.html.haml
index 2b58c865b2e..87dad6140be 100644
--- a/app/views/projects/merge_requests/show/_state_widget.html.haml
+++ b/app/views/projects/merge_requests/show/_state_widget.html.haml
@@ -21,6 +21,12 @@
#{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
= render "projects/merge_requests/show/remove_source_branch"
+ - if @merge_request.locked?
+ %h4
+ Merge in progress...
+ %p
+ GitLab tries to merge it right now. During this time merge request is locked and can not be closed.
+
- unless @commits.any?
%h4 Nothing to merge
%p
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 6c986050c45..f5cd0f21e01 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -44,13 +44,14 @@
.js-toggle-content.hide
.form-group.import-url-data
= f.label :import_url, class: 'control-label' do
- %span Import existing repo
+ %span Import existing git repo
.col-sm-10
= f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git'
.bs-callout.bs-callout-info
This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
%br
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
+ For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
%hr
.form-group
diff --git a/app/views/projects/new_tree/show.html.haml b/app/views/projects/new_tree/show.html.haml
index 49c504c104f..c47c0a3f642 100644
--- a/app/views/projects/new_tree/show.html.haml
+++ b/app/views/projects/new_tree/show.html.haml
@@ -27,14 +27,9 @@
.file-content.code
%pre#editor= params[:content]
- .form-actions
- = hidden_field_tag 'content', '', id: "file-content"
- .commit-button-annotation
- = button_tag "Commit changes", class: 'btn commit-btn js-commit-button btn-create'
- .message
- to branch
- %strong= @ref
- = link_to "Cancel", project_tree_path(@project, @id), class: "btn btn-cancel", data: { confirm: leave_edit_message}
+ = hidden_field_tag 'content', '', id: 'file-content'
+ = render 'projects/commit_button', ref: @ref,
+ cancel_path: project_tree_path(@project, @id)
:javascript
ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace-src-noconflict")
diff --git a/app/views/projects/notes/discussions/_diff.html.haml b/app/views/projects/notes/discussions/_diff.html.haml
index da71220af17..b4d1cce7980 100644
--- a/app/views/projects/notes/discussions/_diff.html.haml
+++ b/app/views/projects/notes/discussions/_diff.html.haml
@@ -21,7 +21,7 @@
- else
%td.old_line= raw(line.type == "new" ? "&nbsp;" : line.old_pos)
%td.new_line= raw(line.type == "old" ? "&nbsp;" : line.new_pos)
- %td.line_content{class: "noteable_line #{line.type} #{line_code}", "line_code" => line_code}= raw "#{line.text} &nbsp;"
+ %td.line_content{class: "noteable_line #{line.type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text)
- if line_code == note.line_code
= render "projects/notes/diff_notes_with_reply", notes: discussion_notes
diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml
index 49a3ef4c8a7..227a2f9a061 100644
--- a/app/views/projects/protected_branches/index.html.haml
+++ b/app/views/projects/protected_branches/index.html.haml
@@ -1,13 +1,13 @@
%h3.page-title Protected branches
-%p.light This ability keeps stable branches secure and forces developers to use code reviews
+%p.light Keep stable branches secure and force developers to use Merge Requests
%hr
.bs-callout.bs-callout-info
%p Protected branches are designed to
%ul
%li prevent pushes from everybody except #{link_to "masters", help_page_path("permissions", "permissions"), class: "vlink"}
- %li prevents anyone from force pushing to the branch
- %li prevents anyone from deleting the branch
+ %li prevent anyone from force pushing to the branch
+ %li prevent anyone from deleting the branch
%p Read more about #{link_to "project permissions", help_page_path("permissions", "permissions"), class: "underlined-link"}
- if can? current_user, :admin_project, @project
diff --git a/app/views/projects/tree/_submodule_item.html.haml b/app/views/projects/tree/_submodule_item.html.haml
index a8ec9df2c8f..46e9be4af83 100644
--- a/app/views/projects/tree/_submodule_item.html.haml
+++ b/app/views/projects/tree/_submodule_item.html.haml
@@ -7,8 +7,8 @@
@
%span.monospace
- if commit.nil?
- #{submodule_item.id[0..10]}
+ #{truncate_sha(submodule_item.id)}
- else
- = link_to "#{submodule_item.id[0..10]}", commit
+ = link_to "#{truncate_sha(submodule_item.id)}", commit
%td
%td.hidden-xs
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index d3a66c48c9b..ef4b8f74714 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -17,7 +17,7 @@
%tr
%td
= link_to project_wiki_path(@project, @page, version_id: commit.id) do
- = commit.id[0..10]
+ = truncate_sha(commit.id)
%td
= commit.author.name
%td
diff --git a/app/views/search/results/_note.html.haml b/app/views/search/results/_note.html.haml
index f2327cd69cc..a44a4542df5 100644
--- a/app/views/search/results/_note.html.haml
+++ b/app/views/search/results/_note.html.haml
@@ -10,7 +10,7 @@
= project.name_with_namespace
&middot;
= link_to project_commit_path(project, note.commit_id, anchor: dom_id(note)) do
- Commit #{note.commit_id[0..8]}
+ Commit #{truncate_sha(note.commit_id)}
- else
= link_to project do
= project.name_with_namespace
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 857643c006e..e7a8d08dc83 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -119,6 +119,7 @@ production: &base
# new_issue_url: "http://jira.sample/secure/CreateIssue.jspa"
## Gravatar
+ ## For Libravatar see: http://doc.gitlab.com/ce/customization/libravatar.html
gravatar:
enabled: true # Use user avatar image from Gravatar.com (default: true)
# gravatar urls: possible placeholders: %{hash} %{size} %{email}
@@ -134,43 +135,61 @@ production: &base
# bundle exec rake gitlab:ldap:check RAILS_ENV=production
ldap:
enabled: false
- host: '_your_ldap_server'
- port: 636
- uid: 'sAMAccountName'
- method: 'ssl' # "tls" or "ssl" or "plain"
- bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
- password: '_the_password_of_the_bind_user'
-
- # This setting specifies if LDAP server is Active Directory LDAP server.
- # For non AD servers it skips the AD specific queries.
- # If your LDAP server is not AD, set this to false.
- active_directory: true
-
- # If allow_username_or_email_login is enabled, GitLab will ignore everything
- # after the first '@' in the LDAP username submitted by the user on login.
- #
- # Example:
- # - the user enters 'jane.doe@example.com' and 'p@ssw0rd' as LDAP credentials;
- # - GitLab queries the LDAP server with 'jane.doe' and 'p@ssw0rd'.
- #
- # If you are using "uid: 'userPrincipalName'" on ActiveDirectory you need to
- # disable this setting, because the userPrincipalName contains an '@'.
- allow_username_or_email_login: false
-
- # Base where we can search for users
- #
- # Ex. ou=People,dc=gitlab,dc=example
- #
- base: ''
-
- # Filter LDAP users
- #
- # Format: RFC 4515 http://tools.ietf.org/search/rfc4515
- # Ex. (employeeType=developer)
- #
- # Note: GitLab does not support omniauth-ldap's custom filter syntax.
- #
- user_filter: ''
+ servers:
+ main: # 'main' is the GitLab 'provider ID' of this LDAP server
+ ## label
+ #
+ # A human-friendly name for your LDAP server. It is OK to change the label later,
+ # for instance if you find out it is too large to fit on the web page.
+ #
+ # Example: 'Paris' or 'Acme, Ltd.'
+ label: 'LDAP'
+
+ host: '_your_ldap_server'
+ port: 636
+ uid: 'sAMAccountName'
+ method: 'ssl' # "tls" or "ssl" or "plain"
+ bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
+ password: '_the_password_of_the_bind_user'
+
+ # This setting specifies if LDAP server is Active Directory LDAP server.
+ # For non AD servers it skips the AD specific queries.
+ # If your LDAP server is not AD, set this to false.
+ active_directory: true
+
+ # If allow_username_or_email_login is enabled, GitLab will ignore everything
+ # after the first '@' in the LDAP username submitted by the user on login.
+ #
+ # Example:
+ # - the user enters 'jane.doe@example.com' and 'p@ssw0rd' as LDAP credentials;
+ # - GitLab queries the LDAP server with 'jane.doe' and 'p@ssw0rd'.
+ #
+ # If you are using "uid: 'userPrincipalName'" on ActiveDirectory you need to
+ # disable this setting, because the userPrincipalName contains an '@'.
+ allow_username_or_email_login: false
+
+ # Base where we can search for users
+ #
+ # Ex. ou=People,dc=gitlab,dc=example
+ #
+ base: ''
+
+ # Filter LDAP users
+ #
+ # Format: RFC 4515 http://tools.ietf.org/search/rfc4515
+ # Ex. (employeeType=developer)
+ #
+ # Note: GitLab does not support omniauth-ldap's custom filter syntax.
+ #
+ user_filter: ''
+
+ # GitLab EE only: add more LDAP servers
+ # Choose an ID made of a-z and 0-9 . This ID will be stored in the database
+ # so that GitLab can remember which LDAP server a user belongs to.
+ # uswest2:
+ # label:
+ # host:
+ # ....
## OmniAuth settings
@@ -299,6 +318,20 @@ test:
project_url: "http://redmine/projects/:issues_tracker_id"
issues_url: "http://redmine/:project_id/:issues_tracker_id/:id"
new_issue_url: "http://redmine/projects/:issues_tracker_id/issues/new"
+ ldap:
+ enabled: false
+ servers:
+ main:
+ label: ldap
+ host: 127.0.0.1
+ port: 3890
+ uid: 'uid'
+ method: 'plain' # "tls" or "ssl" or "plain"
+ base: 'dc=example,dc=com'
+ user_filter: ''
+ group_base: 'ou=groups,dc=example,dc=com'
+ admin_group: ''
+ sync_ssh_keys: false
staging:
<<: *base
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 0d11ae6f33f..88cbaefea7d 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -56,9 +56,25 @@ end
# Default settings
Settings['ldap'] ||= Settingslogic.new({})
Settings.ldap['enabled'] = false if Settings.ldap['enabled'].nil?
-Settings.ldap['allow_username_or_email_login'] = false if Settings.ldap['allow_username_or_email_login'].nil?
-Settings.ldap['active_directory'] = true if Settings.ldap['active_directory'].nil?
+# backwards compatibility, we only have one host
+if Settings.ldap['enabled'] || Rails.env.test?
+ if Settings.ldap['host'].present?
+ server = Settings.ldap.except('sync_time')
+ server['provider_name'] = 'ldap'
+ Settings.ldap['servers'] = {
+ 'ldap' => server
+ }
+ end
+
+ Settings.ldap['servers'].each do |key, server|
+ server['label'] ||= 'LDAP'
+ server['allow_username_or_email_login'] = false if server['allow_username_or_email_login'].nil?
+ server['active_directory'] = true if server['active_directory'].nil?
+ server['provider_name'] ||= "ldap#{key}".downcase
+ server['provider_class'] = OmniAuth::Utils.camelize(server['provider_name'])
+ end
+end
Settings['omniauth'] ||= Settingslogic.new({})
Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil?
diff --git a/config/initializers/7_omniauth.rb b/config/initializers/7_omniauth.rb
new file mode 100644
index 00000000000..18759f0cfb0
--- /dev/null
+++ b/config/initializers/7_omniauth.rb
@@ -0,0 +1,12 @@
+if Gitlab::LDAP::Config.enabled?
+ module OmniAuth::Strategies
+ server = Gitlab.config.ldap.servers.values.first
+ klass = server['provider_class']
+ const_set(klass, Class.new(LDAP)) unless klass == 'LDAP'
+ end
+
+ OmniauthCallbacksController.class_eval do
+ server = Gitlab.config.ldap.servers.values.first
+ alias_method server['provider_name'], :ldap
+ end
+end \ No newline at end of file
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 34f4f386988..c6eb3e51036 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -204,22 +204,24 @@ Devise.setup do |config|
# manager.default_strategies(scope: :user).unshift :some_external_strategy
# end
- if Gitlab.config.ldap.enabled
- if Gitlab.config.ldap.allow_username_or_email_login
- email_stripping_proc = ->(name) {name.gsub(/@.*$/,'')}
- else
- email_stripping_proc = ->(name) {name}
+ if Gitlab::LDAP::Config.enabled?
+ Gitlab.config.ldap.servers.values.each do |server|
+ if server['allow_username_or_email_login']
+ email_stripping_proc = ->(name) {name.gsub(/@.*$/,'')}
+ else
+ email_stripping_proc = ->(name) {name}
+ end
+
+ config.omniauth server['provider_name'],
+ host: server['host'],
+ base: server['base'],
+ uid: server['uid'],
+ port: server['port'],
+ method: server['method'],
+ bind_dn: server['bind_dn'],
+ password: server['password'],
+ name_proc: email_stripping_proc
end
-
- config.omniauth :ldap,
- host: Gitlab.config.ldap['host'],
- base: Gitlab.config.ldap['base'],
- uid: Gitlab.config.ldap['uid'],
- port: Gitlab.config.ldap['port'],
- method: Gitlab.config.ldap['method'],
- bind_dn: Gitlab.config.ldap['bind_dn'],
- password: Gitlab.config.ldap['password'],
- name_proc: email_stripping_proc
end
Gitlab.config.omniauth.providers.each do |provider|
diff --git a/db/fixtures/development/12_snippets.rb b/db/fixtures/development/12_snippets.rb
index ff91e8430a4..b3a6f39c7d5 100644
--- a/db/fixtures/development/12_snippets.rb
+++ b/db/fixtures/development/12_snippets.rb
@@ -1,9 +1,26 @@
Gitlab::Seeder.quiet do
- contents = [
- `curl https://gist.githubusercontent.com/randx/4275756/raw/da2f262920c96d1a970d48bf2e99147954b1f4bd/glus1204.sh`,
- `curl https://gist.githubusercontent.com/randx/3754594/raw/11026a295e6ef3a151c635707a3e1e8e15fc4725/gitlab_setup.sh`,
- `curl https://gist.githubusercontent.com/randx/3065552/raw/29fbd09f4605a5ea22a5a9095e35fd1938dea4d6/gistfile1.sh`,
- ]
+ content =<<eos
+class Member < ActiveRecord::Base
+ include Notifiable
+ include Gitlab::Access
+
+ belongs_to :user
+ belongs_to :source, polymorphic: true
+
+ validates :user, presence: true
+ validates :source, presence: true
+ validates :user_id, uniqueness: { scope: [:source_type, :source_id], message: "already exists in source" }
+ validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true
+
+ scope :guests, -> { where(access_level: GUEST) }
+ scope :reporters, -> { where(access_level: REPORTER) }
+ scope :developers, -> { where(access_level: DEVELOPER) }
+ scope :masters, -> { where(access_level: MASTER) }
+ scope :owners, -> { where(access_level: OWNER) }
+
+ delegate :name, :username, :email, to: :user, prefix: true
+end
+eos
(1..50).each do |i|
user = User.all.sample
@@ -12,10 +29,11 @@ Gitlab::Seeder.quiet do
id: i,
author_id: user.id,
title: Faker::Lorem.sentence(3),
- file_name: Faker::Internet.domain_word + '.sh',
- private: [true, false].sample,
- content: contents.sample,
+ file_name: Faker::Internet.domain_word + '.rb',
+ visibility_level: Gitlab::VisibilityLevel.values.sample,
+ content: content,
}])
+
print('.')
end
end
diff --git a/doc/README.md b/doc/README.md
index 2f90cf14a64..a8e21f75714 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -20,6 +20,7 @@
- [Update](update/README.md) Update guides to upgrade your installation.
- [Welcome message](customization/welcome_message.md) Add a custom welcome message to the sign-in page.
- [Issue closing](customization/issue_closing.md) Customize how to close an issue from commit messages.
+- [Libravatar](customization/libravatar.md) Use Libravatar for user avatars.
## Contributor documentation
diff --git a/doc/customization/libravatar.md b/doc/customization/libravatar.md
new file mode 100644
index 00000000000..4dffd3027a9
--- /dev/null
+++ b/doc/customization/libravatar.md
@@ -0,0 +1,69 @@
+# Use Libravatar service with GitLab
+
+GitLab by default supports [Gravatar](gravatar.com) avatar service.
+Libravatar is a service which delivers your avatar (profile picture) to other websites and their API is
+[heavily based on gravatar](http://wiki.libravatar.org/api/).
+
+This means that it is not complicated to switch to Libravatar avatar service or even self hosted Libravatar server.
+
+# Configuration
+
+In [gitlab.yml gravatar section](https://gitlab.com/gitlab-org/gitlab-ce/blob/672bd3902d86b78d730cea809fce312ec49d39d7/config/gitlab.yml.example#L122) set
+the configuration options as follows:
+
+## For HTTP
+
+```yml
+ gravatar:
+ enabled: true
+ # gravatar urls: possible placeholders: %{hash} %{size} %{email}
+ plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
+```
+
+## For HTTPS
+
+```yml
+ gravatar:
+ enabled: true
+ # gravatar urls: possible placeholders: %{hash} %{size} %{email}
+ ssl_url: "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
+```
+
+## Self-hosted
+
+If you are [running your own libravatar service](http://wiki.libravatar.org/running_your_own/) the url will be different in the configuration
+but the important part is to provide the same placeholders so GitLab can parse the url correctly.
+
+For example, you host a service on `http://libravatar.example.com` the `plain_url` you need to supply in `gitlab.yml` is
+
+`http://libravatar.example.com/avatar/%{hash}?s=%{size}&d=identicon`
+
+
+## Omnibus-gitlab example
+
+In `/etc/gitlab/gitlab.rb`:
+
+#### For http
+
+```ruby
+gitlab_rails['gravatar_enabled'] = true
+gitlab_rails['gravatar_plain_url'] = "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
+```
+
+#### For https
+
+```ruby
+gitlab_rails['gravatar_enabled'] = true
+gitlab_rails['gravatar_ssl_url'] = "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
+```
+
+
+Run `sudo gitlab-ctl reconfigure` for changes to take effect.
+
+
+## Default URL for missing images
+
+[Libravatar supports different sets](http://wiki.libravatar.org/api/) of `missing images` for emails not found on the Libravatar service.
+
+In order to use a different set other than `identicon`, replace `&d=identicon` portion of the url with another supported set.
+For example, you can use `retro` set in which case url would look like: `plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=retro"`
diff --git a/doc/development/ci_setup.md b/doc/development/ci_setup.md
index b3e84183a41..ee16aedafe7 100644
--- a/doc/development/ci_setup.md
+++ b/doc/development/ci_setup.md
@@ -4,28 +4,30 @@ This document describes what services we use for testing GitLab and GitLab CI.
We currently use three CI services to test GitLab:
-1. GitLab CI on [GitHost.io](https://gitlab-ce.githost.io/projects/2/) for the [GitLab.com repo](https://gitlab.com/gitlab-org/gitlab-ce)
+1. GitLab CI on [GitHost.io](https://gitlab-ce.githost.io/projects/4/) for the [GitLab.com repo](https://gitlab.com/gitlab-org/gitlab-ce)
2. GitLab CI at ci.gitlab.org to test the private GitLab B.V. repo at dev.gitlab.org
3. [Semephore](https://semaphoreapp.com/gitlabhq/gitlabhq/) for [GitHub.com repo](https://github.com/gitlabhq/gitlabhq)
| Software @ configuration being tested | GitLab CI (ci.gitlab.org) | GitLab CI (GitHost.io) | Semaphore |
-|---------------------------------------|---------------------------|------------------------|-----------|
-| GitLab CE @ MySQL | ✓ | ✓ | |
-| GitLab CE @ PostgreSQL | | | ✓ |
-| GitLab EE @ MySQL | ✓ | | |
-| GitLab CI @ MySQL | ✓ | | |
-| GitLab CI @ PostgreSQL | | | ✓ |
-| GitLab CI Runner | ✓ | | ✓ |
-| GitLab Shell | ✓ | | ✓ |
-| GitLab Shell | ✓ | | ✓ |
+|---------------------------------------|---------------------------|---------------------------------------------------------------------------|-----------|
+| GitLab CE @ MySQL | ✓ | ✓ [Core team can trigger builds](https://gitlab-ce.githost.io/projects/4) | |
+| GitLab CE @ PostgreSQL | | | ✓ [Core team can trigger builds](https://semaphoreapp.com/gitlabhq/gitlabhq/branches/master) |
+| GitLab EE @ MySQL | ✓ | | |
+| GitLab CI @ MySQL | ✓ | | |
+| GitLab CI @ PostgreSQL | | | ✓ |
+| GitLab CI Runner | ✓ | | ✓ |
+| GitLab Shell | ✓ | | ✓ |
+| GitLab Shell | ✓ | | ✓ |
+
+Core team has access to trigger builds if needed for GitLab CE.
We use [these build scripts](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/doc/examples/build_script_gitlab_ce.md) for testing with GitLab CI.
# Build configuration on [Semaphore](https://semaphoreapp.com/gitlabhq/gitlabhq/) for testing the [GitHub.com repo](https://github.com/gitlabhq/gitlabhq)
-Language: Ruby
-Ruby verion: 2.1.2
-database.yml: pg
+- Language: Ruby
+- Ruby verion: 2.1.2
+- database.yml: pg
Build commands
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 0d1a8da4d1b..7a39f2eec9f 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,5 +1,9 @@
# Installation
+## Consider the Omnibus package installation
+
+Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
+
## Select Version to Install
Make sure you view [this installation guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md) from the branch (version) of GitLab you would like to install. In most cases this should be the highest numbered stable branch (example shown below).
@@ -70,8 +74,8 @@ Is the system packaged Git too old? Remove it and compile from source.
# Download and compile from source
cd /tmp
- curl -L --progress https://www.kernel.org/pub/software/scm/git/git-2.0.0.tar.gz | tar xz
- cd git-2.0.0/
+ curl -L --progress https://www.kernel.org/pub/software/scm/git/git-2.1.2.tar.gz | tar xz
+ cd git-2.1.2/
make prefix=/usr/local all
# Install into /usr/local/bin
@@ -161,9 +165,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
### Clone the Source
# Clone GitLab repository
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-3-stable gitlab
+ sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-4-stable gitlab
-**Note:** You can change `7-3-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `7-4-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 6d96da76ad7..edb7a975503 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -510,6 +510,10 @@ Code above produces next output:
| cell 1 | cell 2 |
| cell 3 | cell 4 |
+**Note**
+
+The row of dashes between the table header and body must have at least three dashes in each column.
+
## References
- This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
diff --git a/doc/update/4.2-to-5.0.md b/doc/update/4.2-to-5.0.md
index 897cd0b91fa..cde679598f7 100644
--- a/doc/update/4.2-to-5.0.md
+++ b/doc/update/4.2-to-5.0.md
@@ -195,6 +195,12 @@ sudo rm -R tmp
sudo -u git -H mkdir tmp
sudo chmod -R u+rwX tmp/
+# create directory for pids, make sure GitLab can write to it
+sudo -u git -H mkdir tmp/pids/
+sudo chmod -R u+rwX tmp/pids/
+
+# if you are already running a newer version of GitLab check that installation guide for other tmp folders you need to create
+
# reboot system
sudo reboot
diff --git a/doc/update/6.x-or-7.x-to-7.3.md b/doc/update/6.x-or-7.x-to-7.4.md
index 171fcb4033a..e923060223b 100644
--- a/doc/update/6.x-or-7.x-to-7.3.md
+++ b/doc/update/6.x-or-7.x-to-7.4.md
@@ -1,6 +1,6 @@
-# From 6.x or 7.x to 7.3
+# From 6.x or 7.x to 7.4
-This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.3.
+This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.4.
## Global issue numbers
@@ -64,13 +64,13 @@ sudo gem install bundler --no-ri --no-rdoc
```bash
cd /home/git/gitlab
sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
```
For GitLab Community Edition:
```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
-sudo -u git -H git checkout 7-3-stable
+sudo -u git -H git checkout 7-4-stable
```
OR
@@ -78,8 +78,7 @@ OR
For GitLab Enterprise Edition:
```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
-sudo -u git -H git checkout 7-3-stable-ee
+sudo -u git -H git checkout 7-4-stable-ee
```
## 4. Install additional packages
@@ -153,14 +152,14 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
TIP: to see what changed in `gitlab.yml.example` in this release use next command:
```
-git diff 6-0-stable:config/gitlab.yml.example 7-3-stable:config/gitlab.yml.example
+git diff 6-0-stable:config/gitlab.yml.example 7-4-stable:config/gitlab.yml.example
```
-* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/config/gitlab.yml.example but with your settings.
-* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/config/unicorn.rb.example but with your settings.
-* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.0.0/config.yml.example but with your settings.
-* HTTP setups: Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/lib/support/nginx/gitlab but with your settings.
-* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-3-stable/lib/support/nginx/gitlab-ssl but with your settings.
+* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/config/gitlab.yml.example but with your settings.
+* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/config/unicorn.rb.example but with your settings.
+* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.0.1/config.yml.example but with your settings.
+* HTTP setups: Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/lib/support/nginx/gitlab but with your settings.
+* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/lib/support/nginx/gitlab-ssl but with your settings.
* Copy rack attack middleware config
```bash
diff --git a/doc/update/7.2-to-7.3.md b/doc/update/7.2-to-7.3.md
index 329b763322a..44f3f8f1a38 100644
--- a/doc/update/7.2-to-7.3.md
+++ b/doc/update/7.2-to-7.3.md
@@ -18,12 +18,12 @@ sudo service gitlab stop
```bash
cd /home/git/gitlab
sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
```
For GitLab Community Edition:
```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout 7-3-stable
```
@@ -32,7 +32,6 @@ OR
For GitLab Enterprise Edition:
```bash
-sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
sudo -u git -H git checkout 7-3-stable-ee
```
diff --git a/doc/update/7.3-to-7.4.md b/doc/update/7.3-to-7.4.md
new file mode 100644
index 00000000000..193f44bb67e
--- /dev/null
+++ b/doc/update/7.3-to-7.4.md
@@ -0,0 +1,217 @@
+# From 7.3 to 7.4
+
+### 0. Backup
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+```
+
+### 1. Stop server
+
+```bash
+sudo service gitlab stop
+```
+
+### 2. Get latest code
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H git fetch --all
+sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
+```
+
+For GitLab Community Edition:
+
+```bash
+sudo -u git -H git checkout 7-4-stable
+```
+
+OR
+
+For GitLab Enterprise Edition:
+
+```bash
+sudo -u git -H git checkout 7-4-stable-ee
+```
+
+### 3. Install libs, migrations, etc.
+
+```bash
+cd /home/git/gitlab
+
+# MySQL installations (note: the line below states '--without ... postgres')
+sudo -u git -H bundle install --without development test postgres --deployment
+
+# PostgreSQL installations (note: the line below states '--without ... mysql')
+sudo -u git -H bundle install --without development test mysql --deployment
+
+# Run database migrations
+sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
+
+# Clean up assets and cache
+sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+```
+
+
+### 4. Configure Redis to use sockets
+
+ # Configure redis to use sockets
+ sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.orig
+ # Disable Redis listening on TCP by setting 'port' to 0
+ sed 's/^port .*/port 0/' /etc/redis/redis.conf.orig | sudo tee /etc/redis/redis.conf
+ # Enable Redis socket for default Debian / Ubuntu path
+ echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf
+ # Be sure redis group can write to the socket, enable only if supported (>= redis 2.4.0).
+ sed -i '/# unixsocketperm/ s/^# unixsocketperm.*/unixsocketperm 0775/' /etc/redis/redis.conf
+ # Activate the changes to redis.conf
+ sudo service redis-server restart
+ # Add git to the redis group
+ sudo usermod -aG redis git
+
+ # Configure Redis connection settings
+ sudo -u git -H cp config/resque.yml.example config/resque.yml
+ # Change the Redis socket path if you are not using the default Debian / Ubuntu configuration
+ sudo -u git -H editor config/resque.yml
+
+ # Configure gitlab-shell to use Redis sockets
+ sudo -u git -H sed -i 's|^ # socket.*| socket: /var/run/redis/redis.sock|' /home/git/gitlab-shell/config.yml
+
+### 5. Update config files
+
+#### New configuration options for gitlab.yml
+
+There are new configuration options available for gitlab.yml. View them with the command below and apply them to your current gitlab.yml.
+
+```
+git diff origin/7-3-stable:config/gitlab.yml.example origin/7-4-stable:config/gitlab.yml.example
+```
+
+#### Change timeout for unicorn
+
+```
+# config/unicorn.rb
+timeout 60
+```
+
+#### Change nginx https settings
+
+* HTTPS setups: Make `/etc/nginx/sites-available/nginx-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-4-stable/lib/support/nginx/gitlab-ssl but with your setting
+
+#### Update database.yml config file(for mysql only) if needed (basically it is required for old gitlab installations)
+
+* Add `collation: utf8_general_ci` to config/database.yml as seen in [config/database.yml.mysql](config/database.yml.mysql)
+
+
+### 6. Start application
+
+ sudo service gitlab start
+ sudo service nginx restart
+
+### 7. Check application status
+
+Check if GitLab and its environment are configured correctly:
+
+ sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+ sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If all items are green, then congratulations upgrade is complete!
+
+### 8. Update OmniAuth configuration
+
+When using Google omniauth login, changes of the Google account required.
+Ensure that `Contacts API` and the `Google+ API` are enabled in the [Google Developers Console](https://console.developers.google.com/).
+More details can be found at the [integration documentation](../integration/google.md).
+
+### 9. Optional optimizations for GitLab setups with MySQL databases
+
+Only applies if running MySQL database created with GitLab 6.7 or earlier. If you are not experiencing any issues you may not need the following instructions however following them will bring your database in line with the latest recommended installation configuration and help avoid future issues. Be sure to follow these directions exactly. These directions should be safe for any MySQL instance but to be sure make a current MySQL database backup beforehand.
+
+```
+# Secure your MySQL installation (added in GitLab 6.2)
+sudo mysql_secure_installation
+
+# Login to MySQL
+mysql -u root -p
+
+# do not type the 'mysql>', this is part of the prompt
+
+# Convert all tables to use the InnoDB storage engine (added in GitLab 6.8)
+SELECT CONCAT('ALTER TABLE gitlabhq_production.', table_name, ' ENGINE=InnoDB;') AS 'Copy & run these SQL statements:' FROM information_schema.tables WHERE table_schema = 'gitlabhq_production' AND `ENGINE` <> 'InnoDB' AND `TABLE_TYPE` = 'BASE TABLE';
+
+# If previous query returned results, copy & run all outputed SQL statements
+
+# Convert all tables to correct character set
+SET foreign_key_checks = 0;
+SELECT CONCAT('ALTER TABLE gitlabhq_production.', table_name, ' CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;') AS 'Copy & run these SQL statements:' FROM information_schema.tables WHERE table_schema = 'gitlabhq_production' AND `TABLE_COLLATION` <> 'utf8_unicode_ci' AND `TABLE_TYPE` = 'BASE TABLE';
+
+# If previous query returned results, copy & run all outputed SQL statements
+
+# turn foreign key checks back on
+SET foreign_key_checks = 1;
+
+# Find MySQL users
+mysql> SELECT user FROM mysql.user WHERE user LIKE '%git%';
+
+# If git user exists and gitlab user does not exist
+# you are done with the database cleanup tasks
+mysql> \q
+
+# If both users exist skip to Delete gitlab user
+
+# Create new user for GitLab (changed in GitLab 6.4)
+# change $password in the command below to a real password you pick
+mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY '$password';
+
+# Grant the git user necessary permissions on the database
+mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCK TABLES ON `gitlabhq_production`.* TO 'git'@'localhost';
+
+# Delete the old gitlab user
+mysql> DELETE FROM mysql.user WHERE user='gitlab';
+
+# Quit the database session
+mysql> \q
+
+# Try connecting to the new database with the new user
+sudo -u git -H mysql -u git -p -D gitlabhq_production
+
+# Type the password you replaced $password with earlier
+
+# You should now see a 'mysql>' prompt
+
+# Quit the database session
+mysql> \q
+
+# Update database configuration details
+# See config/database.yml.mysql for latest recommended configuration details
+# Remove the reaping_frequency setting line if it exists (removed in GitLab 6.8)
+# Set production -> pool: 10 (updated in GitLab 5.3)
+# Set production -> username: git
+# Set production -> password: the password your replaced $password with earlier
+sudo -u git -H editor /home/git/gitlab/config/database.yml
+```
+
+
+## Things went south? Revert to previous version (7.3)
+
+### 1. Revert the code to the previous version
+Follow the [upgrade guide from 7.2 to 7.3](7.2-to-7.3.md), except for the database migration
+(The backup is already migrated to the previous version)
+
+### 2. Restore from the backup:
+
+```bash
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
+```
+If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.
+
+
+
+
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 323ee48f3bc..c26d85e9955 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -4,3 +4,5 @@
- [Groups](groups.md)
- [Labels](labels.md)
- [GitLab Flow](gitlab_flow.md)
+- [Notifications](notifications.md)
+- [Migrating from SVN to GitLab](migrating_from_svn.md)
diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md
index 70edea9c8d7..f8fd7c97e2a 100644
--- a/doc/workflow/gitlab_flow.md
+++ b/doc/workflow/gitlab_flow.md
@@ -26,7 +26,7 @@ After getting used to these three steps the branching model becomes the challeng
Since many organizations new to git have no conventions how to work with it, it can quickly become a mess.
The biggest problem they run into is that many long running branches that each contain part of the changes are around.
People have a hard time figuring out which branch they should develop on or deploy to production.
-Frequently the reaction to this problem is to adopt a standardized pattern such as [git flow](http://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](https://guides.github.com/introduction/flow/index.html)
+Frequently the reaction to this problem is to adopt a standardized pattern such as [git flow](http://nvie.com/posts/a-successful-git-branching-model/) and [GitHub flow](http://scottchacon.com/2011/08/31/github-flow.html)
We think there is still room for improvement and will detail a set of practices we call GitLab flow.
# Git flow and its problems
diff --git a/doc/workflow/migrating_from_svn.md b/doc/workflow/migrating_from_svn.md
new file mode 100644
index 00000000000..207e3641802
--- /dev/null
+++ b/doc/workflow/migrating_from_svn.md
@@ -0,0 +1,17 @@
+# Migrating from SVN to GitLab
+
+SVN stands for Subversion and is a version control system (VCS).
+Git is a distributed version control system.
+
+There are some major differences between the two, for more information consult your favourite search engine.
+
+Git has tools for migrating SVN repositories to git, namely `git svn`. You can read more about this at
+[git documentation pages](http://git-scm.com/book/en/Git-and-Other-Systems-Git-and-Subversion).
+
+Apart from the [official git documentation](http://git-scm.com/book/en/Git-and-Other-Systems-Migrating-to-Git) there is also
+user created step by step guide for migrating from SVN to GitLab.
+
+[Benjamin New](https://github.com/leftclickben) wrote [a guide that shows how to do a migration](https://gist.github.com/leftclickben/322b7a3042cbe97ed2af). Mirrors can be found [here](https://gitlab.com/snippets/2168) and [here](https://gist.github.com/maxlazio/f1b593b0d00aa966e9ca).
+
+## Contribute to this guide
+We welcome all contributions that would expand this guide with instructions on how to migrate from SVN and other version control systems.
diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md
new file mode 100644
index 00000000000..3c3ce162df5
--- /dev/null
+++ b/doc/workflow/notifications.md
@@ -0,0 +1,71 @@
+# GitLab Notifications
+
+GitLab has notifications system in place to notify a user of events important for the workflow.
+
+## Notification settings
+
+Under user profile page you can find the notification settings.
+
+![notification settings](notifications/settings.png)
+
+Notification settings are divided into three groups:
+
+* Global Settings
+* Group Settings
+* Project Settings
+
+Each of these settings have levels of notification:
+
+* Disabled - turns off notifications
+* Participating - receive notifications from related resources
+* Watch - receive notifications from projects or groups user is a member of
+* Global - notifications as set at the global settings
+
+#### Global Settings
+
+Global Settings are at the bottom of the hierarchy.
+Any setting set here will be overriden by a setting at the group or a project level.
+
+Group or Project settings can use `global` notification setting which will then use
+anything that is set at Global Settings.
+
+#### Group Settings
+
+Group Settings are taking presedence over Global Settings but are on a level below Project Settings.
+This means that you can set a different level of notifications per group while still being able
+to have a finer level setting per project.
+Organization like this is suitable for users that belong to different groups but don't have the
+same need for being notified for every group they are member of.
+
+#### Project Settings
+
+Project Settings are at the top level and any setting placed at this level will take presedence of any
+other setting.
+This is suitable for users that have different needs for notifications per project basis.
+
+## Notification events
+
+Below is the table of events users can be notified of:
+
+| Event | Sent to | Settings level |
+|------------------------------|-------------------------------------------------------------------|------------------------------|
+| New SSH key added | User | Security email, always sent. |
+| New email added | User | Security email, always sent. |
+| New user created | User | Sent on user creation, except for omniauth (LDAP)|
+| New issue created | Issue assignee [1], project members [2] | [1] not disabled, [2] higher than participating |
+| User added to project | User | Sent when user is added to project |
+| Project access level changed | User | Sent when user project access level is changed |
+| User added to group | User | Sent when user is added to group |
+| Project moved | Project members [1] | [1] not disabled |
+| Group access level changed | User | Sent when user group access level is changed |
+| Close issue | Issue author [1], issue assignee [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
+| Reassign issue | New issue assignee [1], old issue assignee [2] | [1] [2] not disabled |
+| Reopen issue | Project members [1] | [1] higher than participating |
+| New merge request | MR assignee [1] | [1] not disabled |
+| Reassign merge request | New MR assignee [1], old MR assignee [2] | [1] [2] not disabled |
+| Close merge request | MR author [1], MR assignee [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
+| Reopen merge request | Project members [1] | [1] higher than participating |
+| Merge merge request | MR author [1], MR assignee [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
+| New comment | Mentioned users [1], users participating [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
+
+
diff --git a/doc/workflow/notifications/settings.png b/doc/workflow/notifications/settings.png
new file mode 100644
index 00000000000..e5b50ee2494
--- /dev/null
+++ b/doc/workflow/notifications/settings.png
Binary files differ
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index 83f23f66e34..b7d70881d56 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -30,11 +30,21 @@ Feature: Project Source Browse Files
And I edit code
And I fill the new file name
And I fill the commit message
- And I click on "Commit changes"
+ And I click on "Commit Changes"
Then I am redirected to the new file
And I should see its new content
@javascript
+ Scenario: If I enter an illegal file name I see an error message
+ Given I click on "new file" link in repo
+ And I fill the new file name with an illegal name
+ And I edit code
+ And I fill the commit message
+ And I click on "Commit changes"
+ Then I am on the new file page
+ And I see a commit error message
+
+ @javascript
Scenario: I can edit file
Given I click on ".gitignore" file in repo
And I click button "Edit"
@@ -46,10 +56,20 @@ Feature: Project Source Browse Files
And I click button "Edit"
And I edit code
And I fill the commit message
- And I click on "Commit changes"
+ And I click on "Commit Changes"
Then I am redirected to the ".gitignore"
And I should see its new content
+ @javascript @wip
+ Scenario: If I don't change the content of the file I see an error message
+ Given I click on ".gitignore" file in repo
+ And I click button "edit"
+ And I fill the commit message
+ And I click on "Commit changes"
+ # Test fails because carriage returns are added to the file.
+ Then I am on the ".gitignore" edit file page
+ And I see a commit error message
+
@javascript
Scenario: I can see editing preview
Given I click on ".gitignore" file in repo
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index c054e0e8282..935f313e298 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -8,7 +8,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
commit = @project.repository.commit
page.should have_content(@project.name)
page.should have_content(commit.message[0..20])
- page.should have_content(commit.id.to_s[0..5])
+ page.should have_content(commit.short_id)
end
step 'I click atom feed link' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index c009568977d..fae0cec53a6 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -111,7 +111,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step 'I click on the commit in the merge request' do
within '.mr-commits' do
- click_link sample_commit.id[0..8]
+ click_link Commit.truncate_sha(sample_commit.id)
end
end
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index 0642302e797..665f5d6d195 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -61,6 +61,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
fill_in :file_name, with: new_file_name
end
+ step 'I fill the new file name with an illegal name' do
+ fill_in :file_name, with: '.git'
+ end
+
step 'I fill the commit message' do
fill_in :commit_message, with: 'Not yet a commit message.'
end
@@ -69,8 +73,8 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
click_link 'Diff'
end
- step 'I click on "Commit changes"' do
- click_button 'Commit changes'
+ step 'I click on "Commit Changes"' do
+ click_button 'Commit Changes'
end
step 'I click on "Remove"' do
@@ -151,6 +155,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
expect(page).not_to have_link('permalink')
end
+ step 'I see a commit error message' do
+ expect(page).to have_content('Your changes could not be committed')
+ end
+
private
def set_new_content
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 1f238f8befd..5f292255ce1 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -265,6 +265,15 @@ module SharedPaths
visit project_blob_path(@project, File.join(root_ref, '.gitignore'))
end
+ step 'I am on the new file page' do
+ current_path.should eq(project_new_tree_path(@project, root_ref))
+ end
+
+ step 'I am on the ".gitignore" edit file page' do
+ current_path.should eq(project_edit_tree_path(
+ @project, File.join(root_ref, '.gitignore')))
+ end
+
step 'I visit project source page for "6d39438"' do
visit project_tree_path(@project, "6d39438")
end
diff --git a/lib/api/files.rb b/lib/api/files.rb
index e63e635a4d3..84e1d311781 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -85,7 +85,7 @@ module API
branch_name: branch_name
}
else
- render_api_error!(result[:error], 400)
+ render_api_error!(result[:message], 400)
end
end
@@ -117,7 +117,7 @@ module API
branch_name: branch_name
}
else
- render_api_error!(result[:error], 400)
+ render_api_error!(result[:message], 400)
end
end
@@ -149,7 +149,7 @@ module API
branch_name: branch_name
}
else
- render_api_error!(result[:error], 400)
+ render_api_error!(result[:message], 400)
end
end
end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 955abc1bedd..ae33c529b93 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -3,22 +3,16 @@ module Gitlab
def find(login, password)
user = User.find_by(email: login) || User.find_by(username: login)
+ # If no user is found, or it's an LDAP server, try LDAP.
+ # LDAP users are only authenticated via LDAP
if user.nil? || user.ldap_user?
# Second chance - try LDAP authentication
- return nil unless ldap_conf.enabled
+ return nil unless Gitlab::LDAP::Config.enabled?
- Gitlab::LDAP::User.authenticate(login, password)
+ Gitlab::LDAP::Authentication.login(login, password)
else
user if user.valid_password?(password)
end
end
-
- def log
- Gitlab::AppLogger
- end
-
- def ldap_conf
- @ldap_conf ||= Gitlab.config.ldap
- end
end
end
diff --git a/lib/gitlab/ldap/access.rb b/lib/gitlab/ldap/access.rb
index d2235d2e3bc..eb2c4e48ff2 100644
--- a/lib/gitlab/ldap/access.rb
+++ b/lib/gitlab/ldap/access.rb
@@ -1,18 +1,21 @@
+# LDAP authorization model
+#
+# * Check if we are allowed access (not blocked)
+#
module Gitlab
module LDAP
class Access
- attr_reader :adapter
+ attr_reader :adapter, :provider, :user
- def self.open(&block)
- Gitlab::LDAP::Adapter.open do |adapter|
- block.call(self.new(adapter))
+ def self.open(user, &block)
+ Gitlab::LDAP::Adapter.open(user.provider) do |adapter|
+ block.call(self.new(user, adapter))
end
end
def self.allowed?(user)
- self.open do |access|
- if access.allowed?(user)
- # GitLab EE LDAP code goes here
+ self.open(user) do |access|
+ if access.allowed?
user.last_credential_check_at = Time.now
user.save
true
@@ -22,21 +25,30 @@ module Gitlab
end
end
- def initialize(adapter=nil)
+ def initialize(user, adapter=nil)
@adapter = adapter
+ @user = user
+ @provider = user.provider
end
- def allowed?(user)
+ def allowed?
if Gitlab::LDAP::Person.find_by_dn(user.extern_uid, adapter)
- if Gitlab.config.ldap.active_directory
- !Gitlab::LDAP::Person.disabled_via_active_directory?(user.extern_uid, adapter)
- end
+ return true unless ldap_config.active_directory
+ !Gitlab::LDAP::Person.disabled_via_active_directory?(user.extern_uid, adapter)
else
false
end
rescue
false
end
+
+ def adapter
+ @adapter ||= Gitlab::LDAP::Adapter.new(provider)
+ end
+
+ def ldap_config
+ Gitlab::LDAP::Config.new(provider)
+ end
end
end
end
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index 68ac1b22909..c4d0a20d89a 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -1,52 +1,25 @@
module Gitlab
module LDAP
class Adapter
- attr_reader :ldap
+ attr_reader :provider, :ldap
- def self.open(&block)
- Net::LDAP.open(adapter_options) do |ldap|
- block.call(self.new(ldap))
+ def self.open(provider, &block)
+ Net::LDAP.open(config(provider).adapter_options) do |ldap|
+ block.call(self.new(provider, ldap))
end
end
- def self.config
- Gitlab.config.ldap
+ def self.config(provider)
+ Gitlab::LDAP::Config.new(provider)
end
- def self.adapter_options
- encryption =
- case config['method'].to_s
- when 'ssl'
- :simple_tls
- when 'tls'
- :start_tls
- else
- nil
- end
-
- options = {
- host: config['host'],
- port: config['port'],
- encryption: encryption
- }
-
- auth_options = {
- auth: {
- method: :simple,
- username: config['bind_dn'],
- password: config['password']
- }
- }
-
- if config['password'] || config['bind_dn']
- options.merge!(auth_options)
- end
- options
+ def initialize(provider, ldap=nil)
+ @provider = provider
+ @ldap = ldap || Net::LDAP.new(config.adapter_options)
end
-
- def initialize(ldap=nil)
- @ldap = ldap || Net::LDAP.new(self.class.adapter_options)
+ def config
+ Gitlab::LDAP::Config.new(provider)
end
def users(field, value)
@@ -57,13 +30,13 @@ module Gitlab
}
else
options = {
- base: config['base'],
+ base: config.base,
filter: Net::LDAP::Filter.eq(field, value)
}
end
- if config['user_filter'].present?
- user_filter = Net::LDAP::Filter.construct(config['user_filter'])
+ if config.user_filter.present?
+ user_filter = Net::LDAP::Filter.construct(config.user_filter)
options[:filter] = if options[:filter]
Net::LDAP::Filter.join(options[:filter], user_filter)
@@ -77,7 +50,7 @@ module Gitlab
end
entries.map do |entry|
- Gitlab::LDAP::Person.new(entry)
+ Gitlab::LDAP::Person.new(entry, provider)
end
end
@@ -105,12 +78,6 @@ module Gitlab
results
end
end
-
- private
-
- def config
- @config ||= self.class.config
- end
end
end
end
diff --git a/lib/gitlab/ldap/authentication.rb b/lib/gitlab/ldap/authentication.rb
new file mode 100644
index 00000000000..a5944f96983
--- /dev/null
+++ b/lib/gitlab/ldap/authentication.rb
@@ -0,0 +1,71 @@
+# This calls helps to authenticate to LDAP by providing username and password
+#
+# Since multiple LDAP servers are supported, it will loop through all of them
+# until a valid bind is found
+#
+
+module Gitlab
+ module LDAP
+ class Authentication
+ def self.login(login, password)
+ return unless Gitlab::LDAP::Config.enabled?
+ return unless login.present? && password.present?
+
+ auth = nil
+ # loop through providers until valid bind
+ providers.find do |provider|
+ auth = new(provider)
+ auth.login(login, password) # true will exit the loop
+ end
+
+ # If (login, password) was invalid for all providers, the value of auth is now the last
+ # Gitlab::LDAP::Authentication instance we tried.
+ auth.user
+ end
+
+ def self.providers
+ Gitlab::LDAP::Config.providers
+ end
+
+ attr_accessor :provider, :ldap_user
+
+ def initialize(provider)
+ @provider = provider
+ end
+
+ def login(login, password)
+ @ldap_user = adapter.bind_as(
+ filter: user_filter(login),
+ size: 1,
+ password: password
+ )
+ end
+
+ def adapter
+ OmniAuth::LDAP::Adaptor.new(config.options)
+ end
+
+ def config
+ Gitlab::LDAP::Config.new(provider)
+ end
+
+ def user_filter(login)
+ filter = Net::LDAP::Filter.eq(config.uid, login)
+
+ # Apply LDAP user filter if present
+ if config.user_filter.present?
+ filter = Net::LDAP::Filter.join(
+ filter,
+ Net::LDAP::Filter.construct(config.user_filter)
+ )
+ end
+ filter
+ end
+
+ def user
+ return nil unless ldap_user
+ Gitlab::LDAP::User.find_by_uid_and_provider(ldap_user.dn, provider)
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb
new file mode 100644
index 00000000000..d41bfba9b0f
--- /dev/null
+++ b/lib/gitlab/ldap/config.rb
@@ -0,0 +1,115 @@
+# Load a specific server configuration
+module Gitlab
+ module LDAP
+ class Config
+ attr_accessor :provider, :options
+
+ def self.enabled?
+ Gitlab.config.ldap.enabled
+ end
+
+ def self.servers
+ Gitlab.config.ldap.servers.values
+ end
+
+ def self.providers
+ servers.map {|server| server['provider_name'] }
+ end
+
+ def initialize(provider)
+ @provider = provider
+ invalid_provider unless valid_provider?
+ @options = config_for(provider)
+ end
+
+ def enabled?
+ base_config.enabled
+ end
+
+ def adapter_options
+ {
+ host: options['host'],
+ port: options['port'],
+ encryption: encryption
+ }.tap do |options|
+ options.merge!(auth_options) if has_auth?
+ end
+ end
+
+ def base
+ options['base']
+ end
+
+ def uid
+ options['uid']
+ end
+
+ def sync_ssh_keys?
+ sync_ssh_keys.present?
+ end
+
+ # The LDAP attribute in which the ssh keys are stored
+ def sync_ssh_keys
+ options['sync_ssh_keys']
+ end
+
+ def user_filter
+ options['user_filter']
+ end
+
+ def group_base
+ options['group_base']
+ end
+
+ def admin_group
+ options['admin_group']
+ end
+
+ def active_directory
+ options['active_directory']
+ end
+
+ protected
+ def base_config
+ Gitlab.config.ldap
+ end
+
+ def config_for(provider)
+ base_config.servers.values.find { |server| server['provider_name'] == provider }
+ end
+
+ def encryption
+ case options['method'].to_s
+ when 'ssl'
+ :simple_tls
+ when 'tls'
+ :start_tls
+ else
+ nil
+ end
+ end
+
+ def valid_provider?
+ self.class.providers.include?(provider)
+ end
+
+ def invalid_provider
+ raise "Unknown provider (#{provider}). Available providers: #{self.class.providers}"
+ end
+
+ def auth_options
+ {
+ auth: {
+ method: :simple,
+ username: options['bind_dn'],
+ password: options['password']
+ }
+ }
+ end
+
+ def has_auth?
+ options['password'] || options['bind_dn']
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 87c3d711db4..3e0b3e6cbf8 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -6,24 +6,24 @@ module Gitlab
# Source: http://ctogonewild.com/2009/09/03/bitmask-searches-in-ldap/
AD_USER_DISABLED = Net::LDAP::Filter.ex("userAccountControl:1.2.840.113556.1.4.803", "2")
- def self.find_by_uid(uid, adapter=nil)
- adapter ||= Gitlab::LDAP::Adapter.new
- adapter.user(config.uid, uid)
+ attr_accessor :entry, :provider
+
+ def self.find_by_uid(uid, adapter)
+ adapter.user(adapter.config.uid, uid)
end
- def self.find_by_dn(dn, adapter=nil)
- adapter ||= Gitlab::LDAP::Adapter.new
+ def self.find_by_dn(dn, adapter)
adapter.user('dn', dn)
end
- def self.disabled_via_active_directory?(dn, adapter=nil)
- adapter ||= Gitlab::LDAP::Adapter.new
+ def self.disabled_via_active_directory?(dn, adapter)
adapter.dn_matches_filter?(dn, AD_USER_DISABLED)
end
- def initialize(entry)
+ def initialize(entry, provider)
Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" }
@entry = entry
+ @provider = provider
end
def name
@@ -38,6 +38,10 @@ module Gitlab
uid
end
+ def email
+ entry.try(:mail)
+ end
+
def dn
entry.dn
end
@@ -48,12 +52,8 @@ module Gitlab
@entry
end
- def adapter
- @adapter ||= Gitlab::LDAP::Adapter.new
- end
-
def config
- @config ||= Gitlab.config.ldap
+ @config ||= Gitlab::LDAP::Config.new(provider)
end
end
end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index 25b5a702f9a..3176e9790a7 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -10,77 +10,52 @@ module Gitlab
module LDAP
class User < Gitlab::OAuth::User
class << self
- def find_or_create(auth_hash)
- self.auth_hash = auth_hash
- find(auth_hash) || find_and_connect_by_email(auth_hash) || create(auth_hash)
- end
-
- def find_and_connect_by_email(auth_hash)
- self.auth_hash = auth_hash
- user = model.find_by(email: self.auth_hash.email)
-
- if user
- user.update_attributes(extern_uid: auth_hash.uid, provider: auth_hash.provider)
- Gitlab::AppLogger.info("(LDAP) Updating legacy LDAP user #{self.auth_hash.email} with extern_uid => #{auth_hash.uid}")
- return user
- end
- end
-
- def authenticate(login, password)
- # Check user against LDAP backend if user is not authenticated
- # Only check with valid login and password to prevent anonymous bind results
- return nil unless ldap_conf.enabled && login.present? && password.present?
-
- ldap_user = adapter.bind_as(
- filter: user_filter(login),
- size: 1,
- password: password
- )
-
- find_by_uid(ldap_user.dn) if ldap_user
- end
-
- def adapter
- @adapter ||= OmniAuth::LDAP::Adaptor.new(ldap_conf)
+ def find_by_uid_and_provider(uid, provider)
+ # LDAP distinguished name is case-insensitive
+ ::User.
+ where(provider: [provider, :ldap]).
+ where('lower(extern_uid) = ?', uid.downcase).last
end
+ end
- protected
-
- def find_by_uid_and_provider
- find_by_uid(auth_hash.uid)
- end
+ def initialize(auth_hash)
+ super
+ update_user_attributes
+ end
- def find_by_uid(uid)
- # LDAP distinguished name is case-insensitive
- model.where("provider = ? and lower(extern_uid) = ?", provider, uid.downcase).last
- end
+ # instance methods
+ def gl_user
+ @gl_user ||= find_by_uid_and_provider || find_by_email || build_new_user
+ end
- def provider
- 'ldap'
- end
+ def find_by_uid_and_provider
+ self.class.find_by_uid_and_provider(
+ auth_hash.uid.downcase, auth_hash.provider)
+ end
- def raise_error(message)
- raise OmniAuth::Error, "(LDAP) " + message
- end
+ def find_by_email
+ model.find_by(email: auth_hash.email)
+ end
- def ldap_conf
- Gitlab.config.ldap
- end
+ def update_user_attributes
+ gl_user.attributes = {
+ extern_uid: auth_hash.uid,
+ provider: auth_hash.provider,
+ email: auth_hash.email
+ }
+ end
- def user_filter(login)
- filter = Net::LDAP::Filter.eq(adapter.uid, login)
- # Apply LDAP user filter if present
- if ldap_conf['user_filter'].present?
- user_filter = Net::LDAP::Filter.construct(ldap_conf['user_filter'])
- filter = Net::LDAP::Filter.join(filter, user_filter)
- end
- filter
- end
+ def changed?
+ gl_user.changed?
end
def needs_blocking?
false
end
+
+ def allowed?
+ Gitlab::LDAP::Access.allowed?(gl_user)
+ end
end
end
end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 17512a51658..ddcce7557a0 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -70,14 +70,22 @@ module Gitlab
insert_piece($1)
end
- # Context passed to the markdoqwn pipeline
+ # Used markdown pipelines in GitLab:
+ # GitlabEmojiFilter - performs emoji replacement.
+ #
+ # see https://gitlab.com/gitlab-org/html-pipeline-gitlab for more filters
+ filters = [
+ HTML::Pipeline::Gitlab::GitlabEmojiFilter
+ ]
+
markdown_context = {
- asset_root: File.join(root_url,
- Gitlab::Application.config.assets.prefix)
+ asset_root: Gitlab.config.gitlab.url,
+ asset_host: Gitlab::Application.config.asset_host
}
- result = HTML::Pipeline::Gitlab::MarkdownPipeline.call(text,
- markdown_context)
+ markdown_pipeline = HTML::Pipeline::Gitlab.new(filters).pipeline
+
+ result = markdown_pipeline.call(text, markdown_context)
text = result[:output].to_html(save_with: 0)
allowed_attributes = ActionView::Base.sanitized_allowed_attributes
diff --git a/lib/gitlab/oauth/auth_hash.rb b/lib/gitlab/oauth/auth_hash.rb
index 0198f61f427..ce52beec78e 100644
--- a/lib/gitlab/oauth/auth_hash.rb
+++ b/lib/gitlab/oauth/auth_hash.rb
@@ -21,7 +21,7 @@ module Gitlab
end
def name
- (info.name || full_name).to_s.force_encoding('utf-8')
+ (info.try(:name) || full_name).to_s.force_encoding('utf-8')
end
def full_name
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index b768eda185f..47f62153a50 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -6,55 +6,77 @@
module Gitlab
module OAuth
class User
- class << self
- attr_reader :auth_hash
+ attr_accessor :auth_hash, :gl_user
- def find(auth_hash)
- self.auth_hash = auth_hash
- find_by_uid_and_provider
- end
+ def initialize(auth_hash)
+ self.auth_hash = auth_hash
+ end
- def create(auth_hash)
- user = new(auth_hash)
- user.save_and_trigger_callbacks
- end
+ def persisted?
+ gl_user.try(:persisted?)
+ end
- def model
- ::User
- end
+ def new?
+ !persisted?
+ end
+
+ def valid?
+ gl_user.try(:valid?)
+ end
+
+ def save
+ unauthorized_to_create unless gl_user
- def auth_hash=(auth_hash)
- @auth_hash = AuthHash.new(auth_hash)
+ if needs_blocking?
+ gl_user.save!
+ gl_user.block
+ else
+ gl_user.save!
end
- protected
- def find_by_uid_and_provider
- model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last
+ log.info "(OAuth) saving user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}"
+ gl_user
+ rescue ActiveRecord::RecordInvalid => e
+ log.info "(OAuth) Error saving user: #{gl_user.errors.full_messages}"
+ return self, e.record.errors
+ end
+
+ def gl_user
+ @user ||= find_by_uid_and_provider
+
+ if signup_enabled?
+ @user ||= build_new_user
end
+
+ @user
end
- # Instance methods
- attr_accessor :auth_hash, :user
+ protected
- def initialize(auth_hash)
- self.auth_hash = auth_hash
- self.user = self.class.model.new(user_attributes)
- user.skip_confirmation!
+ def needs_blocking?
+ new? && block_after_signup?
+ end
+
+ def signup_enabled?
+ Gitlab.config.omniauth.allow_single_sign_on
+ end
+
+ def block_after_signup?
+ Gitlab.config.omniauth.block_auto_created_users
end
def auth_hash=(auth_hash)
@auth_hash = AuthHash.new(auth_hash)
end
- def save_and_trigger_callbacks
- user.save!
- log.info "(OAuth) Creating user #{auth_hash.email} from login with extern_uid => #{auth_hash.uid}"
- user.block if needs_blocking?
+ def find_by_uid_and_provider
+ model.where(provider: auth_hash.provider, extern_uid: auth_hash.uid).last
+ end
- user
- rescue ActiveRecord::RecordInvalid => e
- log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}"
- return nil, e.record.errors
+ def build_new_user
+ model.new(user_attributes).tap do |user|
+ user.skip_confirmation!
+ end
end
def user_attributes
@@ -73,12 +95,12 @@ module Gitlab
Gitlab::AppLogger
end
- def raise_error(message)
- raise OmniAuth::Error, "(OAuth) " + message
+ def model
+ ::User
end
- def needs_blocking?
- Gitlab.config.omniauth['block_auto_created_users']
+ def raise_unauthorized_to_create
+ raise StandardError.new("Unauthorized to create user, signup disabled for #{auth_hash.provider}")
end
end
end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index c3378d6a18f..54d740908d5 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -10,6 +10,17 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
super options
end
+ # If project has issue number 39, apostrophe will be linked in
+ # regular text to the issue as Redcarpet will convert apostrophe to
+ # #39;
+ # We replace apostrophe with right single quote before Redcarpet
+ # does the processing and put the apostrophe back in postprocessing.
+ # This only influences regular text, code blocks are untouched.
+ def normal_text(text)
+ return text unless text.present?
+ text.gsub("'", "&rsquo;")
+ end
+
def block_code(code, language)
# New lines are placed to fix an rendering issue
# with code wrapped inside <h1> tag for next case:
@@ -44,6 +55,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
end
def postprocess(full_document)
+ full_document.gsub!("&rsquo;", "'")
unless @template.instance_variable_get("@project_wiki") || @project.nil?
full_document = h.create_relative_links(full_document)
end
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index d3fb467ef27..fd4f93c2f92 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -91,8 +91,7 @@ server {
# resolver_timeout 10s;
## [Optional] Generate a stronger DHE parameter:
- ## cd /etc/ssl/certs
- ## sudo openssl dhparam -out dhparam.pem 4096
+ ## sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096
##
# ssl_dhparam /etc/ssl/certs/dhparam.pem;
diff --git a/spec/factories.rb b/spec/factories.rb
index a960571206c..15899d8c3c4 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -24,6 +24,11 @@ FactoryGirl.define do
admin true
end
+ trait :ldap do
+ provider 'ldapmain'
+ extern_uid 'my-ldap-id'
+ end
+
factory :admin, traits: [:admin]
end
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
new file mode 100644
index 00000000000..4de54d291f2
--- /dev/null
+++ b/spec/helpers/events_helper_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe EventsHelper do
+ include ApplicationHelper
+ include GitlabMarkdownHelper
+
+ it 'should display one line of plain text without alteration' do
+ input = 'A short, plain note'
+ expect(event_note(input)).to match(input)
+ expect(event_note(input)).not_to match(/\.\.\.\z/)
+ end
+
+ it 'should display inline code' do
+ input = 'A note with `inline code`'
+ expected = 'A note with <code>inline code</code>'
+
+ expect(event_note(input)).to match(expected)
+ end
+
+ it 'should truncate a note with multiple paragraphs' do
+ input = "Paragraph 1\n\nParagraph 2"
+ expected = 'Paragraph 1...'
+
+ expect(event_note(input)).to match(expected)
+ end
+
+ it 'should display the first line of a code block' do
+ input = "```\nCode block\nwith two lines\n```"
+ expected = '<pre><code class="">Code block...</code></pre>'
+
+ expect(event_note(input)).to match(expected)
+ end
+
+ it 'should truncate a single long line of text' do
+ text = 'The quick brown fox jumped over the lazy dog twice' # 50 chars
+ input = "#{text}#{text}#{text}#{text}" # 200 chars
+ expected = "#{text}#{text}".sub(/.{3}/, '...')
+
+ expect(event_note(input)).to match(expected)
+ end
+
+ it 'should preserve a link href when link text is truncated' do
+ text = 'The quick brown fox jumped over the lazy dog' # 44 chars
+ input = "#{text}#{text}#{text} " # 133 chars
+ link_url = 'http://example.com/foo/bar/baz' # 30 chars
+ input << link_url
+ expected_link_text = 'http://example...</a>'
+
+ expect(event_note(input)).to match(link_url)
+ expect(event_note(input)).to match(expected_link_text)
+ end
+end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 15033f07432..61751a82369 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -60,7 +60,7 @@ describe GitlabMarkdownHelper do
end
it "should link using a short id" do
- actual = "Backported from #{commit.short_id(6)}"
+ actual = "Backported from #{commit.short_id}"
gfm(actual).should match(expected)
end
@@ -530,6 +530,24 @@ describe GitlabMarkdownHelper do
markdown(actual).should match(%r{<li>light by <a.+>@#{member.user.username}</a></li>})
end
+ it "should not link the apostrophe to issue 39" do
+ project.team << [user, :master]
+ project.issues.stub(:where).with(iid: '39').and_return([issue])
+
+ actual = "Yes, it is @#{member.user.username}'s task."
+ expected = /Yes, it is <a.+>@#{member.user.username}<\/a>'s task/
+ markdown(actual).should match(expected)
+ end
+
+ it "should not link the apostrophe to issue 39 in code blocks" do
+ project.team << [user, :master]
+ project.issues.stub(:where).with(iid: '39').and_return([issue])
+
+ actual = "Yes, `it is @#{member.user.username}'s task.`"
+ expected = /Yes, <code>it is @gfm\'s task.<\/code>/
+ markdown(actual).should match(expected)
+ end
+
it "should handle references in <em>" do
actual = "Apply _!#{merge_request.iid}_ ASAP"
@@ -576,9 +594,21 @@ describe GitlabMarkdownHelper do
end
it "should generate absolute urls for emoji" do
- markdown(":smile:").should include("src=\"#{url_helper('emoji/smile')}")
+ markdown(":smile:").should include("src=\"http://localhost/assets/emoji/smile.png")
+ end
+
+ it "should generate absolute urls for emoji if relative url is present" do
+ Gitlab.config.gitlab.stub(:url).and_return('http://localhost/gitlab/root')
+ markdown(":smile:").should include("src=\"http://localhost/gitlab/root/assets/emoji/smile.png")
end
+ it "should generate absolute urls for emoji if asset_host is present" do
+ Gitlab::Application.config.stub(:asset_host).and_return("https://cdn.example.com")
+ ActionView::Base.any_instance.stub_chain(:config, :asset_host).and_return("https://cdn.example.com")
+ markdown(":smile:").should include("src=\"https://cdn.example.com/assets/emoji/smile.png")
+ end
+
+
it "should handle relative urls for a file in master" do
actual = "[GitLab API doc](doc/api/README.md)\n"
expected = "<p><a href=\"/#{project.path_with_namespace}/blob/#{@ref}/doc/api/README.md\">GitLab API doc</a></p>\n"
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 551fb3fb5f6..1f3e1a4a3c1 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -28,17 +28,16 @@ describe Gitlab::Auth do
end
context "with ldap enabled" do
- before { Gitlab.config.ldap['enabled'] = true }
- after { Gitlab.config.ldap['enabled'] = false }
+ before { Gitlab::LDAP::Config.stub(enabled?: true) }
it "tries to autheticate with db before ldap" do
- expect(Gitlab::LDAP::User).not_to receive(:authenticate)
+ expect(Gitlab::LDAP::Authentication).not_to receive(:login)
gl_auth.find(username, password)
end
it "uses ldap as fallback to for authentication" do
- expect(Gitlab::LDAP::User).to receive(:authenticate)
+ expect(Gitlab::LDAP::Authentication).to receive(:login)
gl_auth.find('ldap_user', 'password')
end
diff --git a/spec/lib/gitlab/ldap/access_spec.rb b/spec/lib/gitlab/ldap/access_spec.rb
index d50f605e050..f4d5a927396 100644
--- a/spec/lib/gitlab/ldap/access_spec.rb
+++ b/spec/lib/gitlab/ldap/access_spec.rb
@@ -1,11 +1,11 @@
require 'spec_helper'
describe Gitlab::LDAP::Access do
- let(:access) { Gitlab::LDAP::Access.new }
- let(:user) { create(:user) }
+ let(:access) { Gitlab::LDAP::Access.new user }
+ let(:user) { create(:user, :ldap) }
describe :allowed? do
- subject { access.allowed?(user) }
+ subject { access.allowed? }
context 'when the user cannot be found' do
before { Gitlab::LDAP::Person.stub(find_by_dn: nil) }
@@ -28,20 +28,14 @@ describe Gitlab::LDAP::Access do
it { should be_true }
end
- context 'and has no disabled flag in active diretory' do
- before {
- Gitlab::LDAP::Person.stub(disabled_via_active_directory?: false)
- Gitlab.config.ldap['enabled'] = true
- Gitlab.config.ldap['active_directory'] = false
- }
-
- after {
- Gitlab.config.ldap['enabled'] = false
- Gitlab.config.ldap['active_directory'] = true
- }
+ context 'without ActiveDirectory enabled' do
+ before do
+ Gitlab::LDAP::Config.stub(enabled?: true)
+ Gitlab::LDAP::Config.any_instance.stub(active_directory: false)
+ end
- it { should be_false }
+ it { should be_true }
end
end
end
-end
+end \ No newline at end of file
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index c3f07334431..19347e47378 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::LDAP::Adapter do
- let(:adapter) { Gitlab::LDAP::Adapter.new }
+ let(:adapter) { Gitlab::LDAP::Adapter.new 'ldapmain' }
describe :dn_matches_filter? do
let(:ldap) { double(:ldap) }
diff --git a/spec/lib/gitlab/ldap/authentication_spec.rb b/spec/lib/gitlab/ldap/authentication_spec.rb
new file mode 100644
index 00000000000..0eb7c443b8b
--- /dev/null
+++ b/spec/lib/gitlab/ldap/authentication_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+describe Gitlab::LDAP::Authentication do
+ let(:klass) { Gitlab::LDAP::Authentication }
+ let(:user) { create(:user, :ldap, extern_uid: dn) }
+ let(:dn) { 'uid=john,ou=people,dc=example,dc=com' }
+ let(:login) { 'john' }
+ let(:password) { 'password' }
+
+ describe :login do
+ let(:adapter) { double :adapter }
+ before do
+ Gitlab::LDAP::Config.stub(enabled?: true)
+ end
+
+ it "finds the user if authentication is successful" do
+ user
+ # try only to fake the LDAP call
+ klass.any_instance.stub(adapter: double(:adapter,
+ bind_as: double(:ldap_user, dn: dn)
+ ))
+ expect(klass.login(login, password)).to be_true
+ end
+
+ it "is false if the user does not exist" do
+ # try only to fake the LDAP call
+ klass.any_instance.stub(adapter: double(:adapter,
+ bind_as: double(:ldap_user, dn: dn)
+ ))
+ expect(klass.login(login, password)).to be_false
+ end
+
+ it "is false if authentication fails" do
+ user
+ # try only to fake the LDAP call
+ klass.any_instance.stub(adapter: double(:adapter, bind_as: nil))
+ expect(klass.login(login, password)).to be_false
+ end
+
+ it "fails if ldap is disabled" do
+ Gitlab::LDAP::Config.stub(enabled?: false)
+ expect(klass.login(login, password)).to be_false
+ end
+
+ it "fails if no login is supplied" do
+ expect(klass.login('', password)).to be_false
+ end
+
+ it "fails if no password is supplied" do
+ expect(klass.login(login, '')).to be_false
+ end
+ end
+end \ No newline at end of file
diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb
new file mode 100644
index 00000000000..76cc7f95c47
--- /dev/null
+++ b/spec/lib/gitlab/ldap/config_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Gitlab::LDAP::Config do
+ let(:config) { Gitlab::LDAP::Config.new provider }
+ let(:provider) { 'ldapmain' }
+
+ describe :initalize do
+ it 'requires a provider' do
+ expect{ Gitlab::LDAP::Config.new }.to raise_error ArgumentError
+ end
+
+ it "works" do
+ expect(config).to be_a described_class
+ end
+
+ it "raises an error if a unknow provider is used" do
+ expect{ Gitlab::LDAP::Config.new 'unknown' }.to raise_error
+ end
+ end
+end \ No newline at end of file
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index d232cb20759..726c9764e3d 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -1,54 +1,36 @@
require 'spec_helper'
describe Gitlab::LDAP::User do
- let(:gl_user) { Gitlab::LDAP::User }
+ let(:gl_user) { Gitlab::LDAP::User.new(auth_hash) }
let(:info) do
- double(
+ {
name: 'John',
email: 'john@example.com',
nickname: 'john'
- )
+ }
+ end
+ let(:auth_hash) do
+ double(uid: 'my-uid', provider: 'ldapmain', info: double(info))
end
- before { Gitlab.config.stub(omniauth: {}) }
describe :find_or_create do
- let(:auth) do
- double(info: info, provider: 'ldap', uid: 'my-uid')
- end
-
it "finds the user if already existing" do
- existing_user = create(:user, extern_uid: 'my-uid', provider: 'ldap')
+ existing_user = create(:user, extern_uid: 'my-uid', provider: 'ldapmain')
- expect{ gl_user.find_or_create(auth) }.to_not change{ User.count }
+ expect{ gl_user.save }.to_not change{ User.count }
end
it "connects to existing non-ldap user if the email matches" do
existing_user = create(:user, email: 'john@example.com')
- expect{ gl_user.find_or_create(auth) }.to_not change{ User.count }
+ expect{ gl_user.save }.to_not change{ User.count }
existing_user.reload
expect(existing_user.extern_uid).to eql 'my-uid'
- expect(existing_user.provider).to eql 'ldap'
+ expect(existing_user.provider).to eql 'ldapmain'
end
it "creates a new user if not found" do
- expect{ gl_user.find_or_create(auth) }.to change{ User.count }.by(1)
- end
- end
-
- describe "authenticate" do
- let(:login) { 'john' }
- let(:password) { 'my-secret' }
-
- before {
- Gitlab.config.ldap['enabled'] = true
- Gitlab.config.ldap['user_filter'] = 'employeeType=developer'
- }
- after { Gitlab.config.ldap['enabled'] = false }
-
- it "send an authentication request to ldap" do
- expect( Gitlab::LDAP::User.adapter ).to receive(:bind_as)
- Gitlab::LDAP::User.authenticate(login, password)
+ expect{ gl_user.save }.to change{ User.count }.by(1)
end
end
end
diff --git a/spec/lib/gitlab/oauth/auth_hash_spec.rb b/spec/lib/gitlab/oauth/auth_hash_spec.rb
new file mode 100644
index 00000000000..5eb77b492b2
--- /dev/null
+++ b/spec/lib/gitlab/oauth/auth_hash_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Gitlab::OAuth::AuthHash do
+ let(:auth_hash) do
+ Gitlab::OAuth::AuthHash.new(double({
+ provider: 'twitter',
+ uid: uid,
+ info: double(info_hash)
+ }))
+ end
+ let(:uid) { 'my-uid' }
+ let(:email) { 'my-email@example.com' }
+ let(:nickname) { 'my-nickname' }
+ let(:info_hash) {
+ {
+ email: email,
+ nickname: nickname,
+ name: 'John',
+ first_name: "John",
+ last_name: "Who"
+ }
+ }
+
+ context "defaults" do
+ it { expect(auth_hash.provider).to eql 'twitter' }
+ it { expect(auth_hash.uid).to eql uid }
+ it { expect(auth_hash.email).to eql email }
+ it { expect(auth_hash.username).to eql nickname }
+ it { expect(auth_hash.name).to eql "John" }
+ it { expect(auth_hash.password).to_not be_empty }
+ end
+
+ context "email not provided" do
+ before { info_hash.delete(:email) }
+ it "generates a temp email" do
+ expect( auth_hash.email).to start_with('temp-email-for-oauth')
+ end
+ end
+
+ context "username not provided" do
+ before { info_hash.delete(:nickname) }
+
+ it "takes the first part of the email as username" do
+ expect( auth_hash.username ).to eql "my-email"
+ end
+ end
+
+ context "name not provided" do
+ before { info_hash.delete(:name) }
+
+ it "concats first and lastname as the name" do
+ expect( auth_hash.name ).to eql "John Who"
+ end
+ end
+end \ No newline at end of file
diff --git a/spec/lib/gitlab/oauth/user_spec.rb b/spec/lib/gitlab/oauth/user_spec.rb
index c241e198609..8a83a1b2588 100644
--- a/spec/lib/gitlab/oauth/user_spec.rb
+++ b/spec/lib/gitlab/oauth/user_spec.rb
@@ -1,83 +1,108 @@
require 'spec_helper'
describe Gitlab::OAuth::User do
- let(:gl_auth) { Gitlab::OAuth::User }
- let(:info) do
- double(
+ let(:oauth_user) { Gitlab::OAuth::User.new(auth_hash) }
+ let(:gl_user) { oauth_user.gl_user }
+ let(:uid) { 'my-uid' }
+ let(:provider) { 'my-provider' }
+ let(:auth_hash) { double(uid: uid, provider: provider, info: double(info_hash)) }
+ let(:info_hash) do
+ {
nickname: 'john',
name: 'John',
email: 'john@mail.com'
- )
+ }
end
- before do
- Gitlab.config.stub(omniauth: {})
- end
-
- describe :find do
+ describe :persisted? do
let!(:existing_user) { create(:user, extern_uid: 'my-uid', provider: 'my-provider') }
it "finds an existing user based on uid and provider (facebook)" do
auth = double(info: double(name: 'John'), uid: 'my-uid', provider: 'my-provider')
- assert gl_auth.find(auth)
+ expect( oauth_user.persisted? ).to be_true
end
- it "finds an existing user based on nested uid and provider" do
- auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
- assert gl_auth.find(auth)
+ it "returns false if use is not found in database" do
+ auth_hash.stub(uid: 'non-existing')
+ expect( oauth_user.persisted? ).to be_false
end
end
- describe :create do
- it "should create user from LDAP" do
- auth = double(info: info, uid: 'my-uid', provider: 'ldap')
- user = gl_auth.create(auth)
+ describe :save do
+ let(:provider) { 'twitter' }
- user.should be_valid
- user.extern_uid.should == auth.uid
- user.provider.should == 'ldap'
- end
+ describe 'signup' do
+ context "with allow_single_sign_on enabled" do
+ before { Gitlab.config.omniauth.stub allow_single_sign_on: true }
- it "should create user from Omniauth" do
- auth = double(info: info, uid: 'my-uid', provider: 'twitter')
- user = gl_auth.create(auth)
+ it "creates a user from Omniauth" do
+ oauth_user.save
- user.should be_valid
- user.extern_uid.should == auth.uid
- user.provider.should == 'twitter'
+ expect(gl_user).to be_valid
+ expect(gl_user.extern_uid).to eql uid
+ expect(gl_user.provider).to eql 'twitter'
+ end
+ end
+
+ context "with allow_single_sign_on disabled (Default)" do
+ it "throws an error" do
+ expect{ oauth_user.save }.to raise_error StandardError
+ end
+ end
end
- it "should apply defaults to user" do
- auth = double(info: info, uid: 'my-uid', provider: 'ldap')
- user = gl_auth.create(auth)
+ describe 'blocking' do
+ let(:provider) { 'twitter' }
+ before { Gitlab.config.omniauth.stub allow_single_sign_on: true }
- user.should be_valid
- user.projects_limit.should == Gitlab.config.gitlab.default_projects_limit
- user.can_create_group.should == Gitlab.config.gitlab.default_can_create_group
- end
+ context 'signup' do
+ context 'dont block on create' do
+ before { Gitlab.config.omniauth.stub block_auto_created_users: false }
- it "Set a temp email address if not provided (like twitter does)" do
- info = double(
- uid: 'my-uid',
- nickname: 'john',
- name: 'John'
- )
- auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
+ it do
+ oauth_user.save
+ gl_user.should be_valid
+ gl_user.should_not be_blocked
+ end
+ end
- user = gl_auth.create(auth)
- expect(user.email).to_not be_empty
- end
+ context 'block on create' do
+ before { Gitlab.config.omniauth.stub block_auto_created_users: true }
+
+ it do
+ oauth_user.save
+ gl_user.should be_valid
+ gl_user.should be_blocked
+ end
+ end
+ end
+
+ context 'sign-in' do
+ before do
+ oauth_user.save
+ oauth_user.gl_user.activate
+ end
+
+ context 'dont block on create' do
+ before { Gitlab.config.omniauth.stub block_auto_created_users: false }
+
+ it do
+ oauth_user.save
+ gl_user.should be_valid
+ gl_user.should_not be_blocked
+ end
+ end
- it 'generates a username if non provided (google)' do
- info = double(
- uid: 'my-uid',
- name: 'John',
- email: 'john@example.com'
- )
- auth = double(info: info, uid: 'my-uid', provider: 'my-provider')
+ context 'block on create' do
+ before { Gitlab.config.omniauth.stub block_auto_created_users: true }
- user = gl_auth.create(auth)
- expect(user.username).to eql 'john'
+ it do
+ oauth_user.save
+ gl_user.should be_valid
+ gl_user.should_not be_blocked
+ end
+ end
+ end
end
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 6f201adc4e8..a6ec44da4be 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -75,7 +75,7 @@ eos
it_behaves_like 'a mentionable' do
let(:subject) { commit }
let(:mauthor) { create :user, email: commit.author_email }
- let(:backref_text) { "commit #{subject.sha[0..5]}" }
+ let(:backref_text) { "commit #{subject.id}" }
let(:set_mentionable_text) { ->(txt){ subject.stub(safe_message: txt) } }
# Include the subject in the repository stub.
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index eeecd714a28..2d839e9611b 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -228,7 +228,7 @@ describe Note do
it { should be_valid }
its(:noteable) { should == issue }
- its(:note) { should == "_mentioned in commit #{commit.sha[0..5]}_" }
+ its(:note) { should == "_mentioned in commit #{commit.sha}_" }
end
context 'merge request from an issue' do
@@ -267,7 +267,7 @@ describe Note do
its(:noteable_type) { should == "Commit" }
its(:noteable_id) { should be_nil }
its(:commit_id) { should == commit.id }
- its(:note) { should == "_mentioned in commit #{parent_commit.id[0...6]}_" }
+ its(:note) { should == "_mentioned in commit #{parent_commit.id}_" }
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 0250014bc21..6ad57b06e06 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -346,6 +346,25 @@ describe User do
end
end
+ describe :ldap_user? do
+ let(:user) { build(:user, :ldap) }
+
+ it "is true if provider name starts with ldap" do
+ user.provider = 'ldapmain'
+ expect( user.ldap_user? ).to be_true
+ end
+
+ it "is false for other providers" do
+ user.provider = 'other-provider'
+ expect( user.ldap_user? ).to be_false
+ end
+
+ it "is false if no extern_uid is provided" do
+ user.extern_uid = nil
+ expect( user.ldap_user? ).to be_false
+ end
+ end
+
describe '#full_website_url' do
let(:user) { create(:user) }
@@ -429,4 +448,32 @@ describe User do
expect(user.starred?(project)).to be_false
end
end
+
+ describe "#sort" do
+ before do
+ User.delete_all
+ @user = create :user, created_at: Date.today, last_sign_in_at: Date.today, name: 'Alpha'
+ @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
+ end
+
+ it "sorts users as recently_signed_in" do
+ User.sort('recent_sign_in').first.should == @user
+ end
+
+ it "sorts users as late_signed_in" do
+ User.sort('oldest_sign_in').first.should == @user1
+ end
+
+ it "sorts users as recently_created" do
+ User.sort('recently_created').first.should == @user
+ end
+
+ it "sorts users as late_created" do
+ User.sort('late_created').first.should == @user1
+ end
+
+ it "sorts users by name when nil is passed" do
+ User.sort(nil).first.should == @user
+ end
+ end
end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index 692834c9f29..ebd74206699 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -30,15 +30,15 @@ def common_mentionable_setup
"!#{mentioned_mr.iid}, " +
"#{ext_proj.path_with_namespace}##{ext_issue.iid}, " +
"#{ext_proj.path_with_namespace}!#{ext_mr.iid}, " +
- "#{ext_proj.path_with_namespace}@#{ext_commit.id[0..5]}, " +
- "#{mentioned_commit.sha[0..5]} and itself as #{backref_text}"
+ "#{ext_proj.path_with_namespace}@#{ext_commit.short_id}, " +
+ "#{mentioned_commit.sha[0..10]} and itself as #{backref_text}"
end
before do
# Wire the project's repository to return the mentioned commit, and +nil+ for any
# unrecognized commits.
- commitmap = { '123456' => mentioned_commit }
- extra_commits.each { |c| commitmap[c.sha[0..5]] = c }
+ commitmap = { '1234567890a' => mentioned_commit }
+ extra_commits.each { |c| commitmap[c.short_id] = c }
mproject.repository.stub(:commit) { |sha| commitmap[sha] }
set_mentionable_text.call(ref_string)
end
@@ -54,7 +54,6 @@ shared_examples 'a mentionable' do
it "extracts references from its reference property" do
# De-duplicate and omit itself
refs = subject.references(mproject)
-
refs.should have(6).items
refs.should include(mentioned_issue)
refs.should include(mentioned_mr)
@@ -90,7 +89,7 @@ shared_examples 'an editable mentionable' do
it 'creates new cross-reference notes when the mentionable text is edited' do
new_text = "still mentions ##{mentioned_issue.iid}, " +
- "#{mentioned_commit.sha[0..5]}, " +
+ "#{mentioned_commit.sha[0..10]}, " +
"#{ext_issue.iid}, " +
"new refs: ##{other_issue.iid}, " +
"#{ext_proj.path_with_namespace}##{other_ext_issue.iid}"