summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG10
-rw-r--r--Gemfile6
-rw-r--r--Gemfile.lock24
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/application.js.coffee15
-rw-r--r--app/assets/stylesheets/base/gl_bootstrap.scss2
-rw-r--r--app/assets/stylesheets/base/mixins.scss1
-rw-r--r--app/assets/stylesheets/pages/notes.scss2
-rw-r--r--app/controllers/admin/application_settings_controller.rb2
-rw-r--r--app/controllers/import/gitorious_controller.rb2
-rw-r--r--app/controllers/projects/services_controller.rb5
-rw-r--r--app/helpers/submodule_helper.rb2
-rw-r--r--app/helpers/visibility_level_helper.rb24
-rw-r--r--app/models/application_setting.rb6
-rw-r--r--app/models/commit_range.rb106
-rw-r--r--app/models/project.rb18
-rw-r--r--app/models/project_services/hipchat_service.rb14
-rw-r--r--app/services/projects/create_service.rb8
-rw-r--r--app/services/projects/fork_service.rb66
-rw-r--r--app/views/admin/application_settings/_form.html.haml8
-rw-r--r--app/views/admin/groups/show.html.haml2
-rw-r--r--app/views/events/event/_created_project.html.haml2
-rw-r--r--app/views/groups/_settings_nav.html.haml8
-rw-r--r--app/views/layouts/_head.html.haml1
-rw-r--r--app/views/layouts/_head_panel.html.haml47
-rw-r--r--app/views/layouts/_page.html.haml4
-rw-r--r--app/views/layouts/nav/_admin.html.haml22
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml14
-rw-r--r--app/views/layouts/nav/_explore.html.haml10
-rw-r--r--app/views/layouts/nav/_group.html.haml12
-rw-r--r--app/views/layouts/nav/_profile.html.haml18
-rw-r--r--app/views/layouts/nav/_project.html.haml28
-rw-r--r--app/views/layouts/nav/_snippets.html.haml4
-rw-r--r--app/views/profiles/update.js.erb8
-rw-r--r--app/views/projects/_settings_nav.html.haml24
-rw-r--r--app/views/projects/_visibility_level.html.haml27
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/new.html.haml2
-rw-r--r--app/views/projects/snippets/edit.html.haml2
-rw-r--r--app/views/projects/snippets/new.html.haml2
-rw-r--r--app/views/shared/_visibility_level.html.haml14
-rw-r--r--app/views/shared/_visibility_radios.html.haml14
-rw-r--r--app/views/shared/snippets/_form.html.haml2
-rw-r--r--app/views/shared/snippets/_visibility_level.html.haml27
-rw-r--r--app/views/snippets/edit.html.haml2
-rw-r--r--app/views/snippets/new.html.haml2
-rw-r--r--config/gitlab.yml.example1
-rw-r--r--db/migrate/20150423033240_add_default_project_visibililty_to_application_settings.rb7
-rw-r--r--db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb7
-rw-r--r--db/schema.rb6
-rw-r--r--doc/integration/gitlab_buttons_in_gmail.md8
-rw-r--r--docker/Dockerfile2
-rw-r--r--docker/README.md44
-rw-r--r--features/steps/dashboard/new_project.rb4
-rw-r--r--features/support/capybara.rb24
-rw-r--r--features/support/db_cleaner.rb11
-rw-r--r--features/support/env.rb30
-rw-r--r--lib/gitlab/contributions_calendar.rb2
-rw-r--r--lib/gitlab/gitorious_import/client.rb2
-rw-r--r--lib/gitlab/markdown/commit_range_reference_filter.rb43
-rw-r--r--lib/gitlab/markdown/commit_reference_filter.rb4
-rw-r--r--lib/gitlab/markdown/issue_reference_filter.rb3
-rw-r--r--lib/gitlab/markdown/label_reference_filter.rb6
-rw-r--r--lib/gitlab/markdown/merge_request_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/reference_filter.rb18
-rw-r--r--lib/gitlab/markdown/snippet_reference_filter.rb2
-rw-r--r--lib/gitlab/markdown/user_reference_filter.rb69
-rw-r--r--lib/gitlab/reference_extractor.rb157
-rw-r--r--lib/gitlab/regex.rb8
-rw-r--r--lib/gitlab/theme.rb39
-rw-r--r--lib/tasks/dev.rake5
-rw-r--r--lib/tasks/gitlab/check.rake3
-rw-r--r--spec/helpers/submodule_helper_spec.rb15
-rw-r--r--spec/helpers/visibility_level_helper_spec.rb75
-rw-r--r--spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb24
-rw-r--r--spec/lib/gitlab/markdown/commit_reference_filter_spec.rb28
-rw-r--r--spec/lib/gitlab/markdown/issue_reference_filter_spec.rb12
-rw-r--r--spec/lib/gitlab/markdown/label_reference_filter_spec.rb5
-rw-r--r--spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb10
-rw-r--r--spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb10
-rw-r--r--spec/lib/gitlab/markdown/user_reference_filter_spec.rb66
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb82
-rw-r--r--spec/lib/gitlab/regex_spec.rb3
-rw-r--r--spec/models/commit_range_spec.rb120
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb16
-rw-r--r--spec/requests/api/fork_spec.rb1
-rw-r--r--spec/services/projects/fork_service_spec.rb16
-rw-r--r--spec/spec_helper.rb8
-rw-r--r--spec/support/capybara.rb21
-rw-r--r--spec/support/mentionable_shared_examples.rb2
-rw-r--r--spec/support/reference_filter_spec_helper.rb14
91 files changed, 1029 insertions, 629 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 92ae6767ea2..33cf1c4378e 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,12 +1,14 @@
Please view this file on the master branch, on stable branches it's out of date.
v 7.11.0 (unreleased)
+ - Get Gitorious importer to work again.
- Fix clone URL field and X11 Primary selection (Dmitry Medvinsky)
- Ignore invalid lines in .gitmodules
- Fix "Cannot move project" error message from popping up after a successful transfer (Stan Hu)
- Redirect to sign in page after signing out.
- Fix "Hello @username." references not working by no longer allowing usernames to end in period.
-
+ - Fix broken file browsing with relative submodule in personal projects (Stan Hu)
- Add "Reply quoting selected text" shortcut key (`r`)
- Fix bug causing `@whatever` inside an issue's first code block to be picked up as a user mention.
- Fix bug causing `@whatever` inside an inline code snippet (backtick-style) to be picked up as a user mention.
@@ -15,16 +17,18 @@ v 7.11.0 (unreleased)
- Add project activity atom feed.
- Don't crash when an MR from a fork has a cross-reference comment from the target project on of its commits.
- Include commit comments in MR from a forked project.
- -
- -
+ - Fix adding new group members from admin area
+ - Add default project and snippet visibility settings to the admin web UI.
- Fix bug where Slack service channel was not saved in admin template settings. (Stan Hu)
- Move snippets UI to fluid layout
- Improve UI for sidebar. Increase separation between navigation and content
- Improve new project command options (Ben Bodenmiller)
- Prevent sending empty messages to HipChat (Chulki Lee)
- Improve UI for mobile phones on dashboard and project pages
+ - Add room notification and message color option for HipChat
+ - Allow to use non-ASCII letters and dashes in project and namespace name. (Jakub Jirutka)
-v 7.10.0 (unreleased)
+v 7.10.0
- Ignore submodules that are defined in .gitmodules but are checked in as directories.
- Allow projects to be imported from Google Code.
- Remove access control for uploaded images to fix broken images in emails (Hannes Rosenögger)
diff --git a/Gemfile b/Gemfile
index 460a0f93a96..ea62396d8a3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -208,6 +208,7 @@ group :development do
gem "letter_opener"
gem 'quiet_assets', '~> 1.0.1'
gem 'rack-mini-profiler', require: false
+ gem 'rerun', '~> 0.10.0'
# Better errors handler
gem 'better_errors'
@@ -223,14 +224,13 @@ end
group :development, :test do
gem 'coveralls', require: false
gem 'rubocop', '0.28.0', require: false
- # gem 'rails-dev-tweaks'
gem 'spinach-rails'
gem "rspec-rails", '2.99'
- gem "capybara", '~> 2.2.1'
+ gem 'capybara', '~> 2.2.1'
+ gem 'capybara-screenshot', '~> 1.0.0'
gem "pry-rails"
gem "awesome_print"
gem "database_cleaner"
- gem "launchy"
gem 'factory_girl_rails'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
diff --git a/Gemfile.lock b/Gemfile.lock
index f0f8601a760..676a5197900 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -47,7 +47,7 @@ GEM
astrolabe (1.3.0)
parser (>= 2.2.0.pre.3, < 3.0)
attr_required (1.0.0)
- autoprefixer-rails (5.1.6)
+ autoprefixer-rails (5.1.11)
execjs
json
awesome_print (1.2.0)
@@ -60,7 +60,7 @@ GEM
erubis (>= 2.6.6)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
- bootstrap-sass (3.3.3)
+ bootstrap-sass (3.3.4.1)
autoprefixer-rails (>= 5.0.0.1)
sass (>= 3.2.19)
brakeman (3.0.1)
@@ -85,6 +85,9 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
+ capybara-screenshot (1.0.9)
+ capybara (>= 1.0, < 3)
+ launchy
carrierwave (0.9.0)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
@@ -151,7 +154,7 @@ GEM
escape_utils (0.2.4)
eventmachine (1.0.4)
excon (0.32.1)
- execjs (2.0.2)
+ execjs (2.5.2)
expression_parser (0.9.0)
factory_girl (4.3.0)
activesupport (>= 3.0.0)
@@ -164,7 +167,7 @@ GEM
faraday (>= 0.7.4, < 0.9)
fastercsv (1.5.5)
ffaker (1.22.1)
- ffi (1.9.3)
+ ffi (1.9.8)
fog (1.21.0)
fog-brightbox
fog-core (~> 1.21, >= 1.21.1)
@@ -320,8 +323,8 @@ GEM
addressable (~> 2.3)
letter_opener (1.1.2)
launchy (~> 2.2)
- listen (2.3.1)
- celluloid (>= 0.15.2)
+ listen (2.10.0)
+ celluloid (~> 0.16.0)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
lumberjack (1.0.4)
@@ -453,8 +456,8 @@ GEM
raindrops (0.13.0)
rake (10.4.2)
raphael-rails (2.1.2)
- rb-fsevent (0.9.3)
- rb-inotify (0.9.2)
+ rb-fsevent (0.9.4)
+ rb-inotify (0.9.5)
ffi (>= 0.5.0)
rdoc (3.12.2)
json (~> 1.4)
@@ -479,6 +482,8 @@ GEM
redis-store (1.1.4)
redis (>= 2.2)
request_store (1.0.5)
+ rerun (0.10.0)
+ listen (~> 2.7, >= 2.7.3)
rest-client (1.6.7)
mime-types (>= 1.16)
rinku (1.7.3)
@@ -677,6 +682,7 @@ DEPENDENCIES
byebug
cal-heatmap-rails (~> 0.0.1)
capybara (~> 2.2.1)
+ capybara-screenshot (~> 1.0.0)
carrierwave
charlock_holmes
coffee-rails
@@ -726,7 +732,6 @@ DEPENDENCIES
jquery-turbolinks
jquery-ui-rails
kaminari (~> 0.15.1)
- launchy
letter_opener
minitest (~> 5.3.0)
mousetrap-rails
@@ -760,6 +765,7 @@ DEPENDENCIES
redcarpet (~> 3.2.3)
redis-rails
request_store
+ rerun (~> 0.10.0)
rspec-rails (= 2.99)
rubocop (= 0.28.0)
rugments
diff --git a/VERSION b/VERSION
index 67fc32adaba..e85691e6ff7 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.10.0.pre
+7.11.0.pre
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 020c103dbc5..bb9da147018 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -132,10 +132,17 @@ $ ->
), 1
# Initialize tooltips
- $('.has_tooltip').tooltip()
-
- # Bottom tooltip
- $('.has_bottom_tooltip').tooltip(placement: 'bottom')
+ $('body').tooltip({
+ selector: '.has_tooltip, [data-toggle="tooltip"], .page-sidebar-collapsed .nav-sidebar a'
+ placement: (_, el) ->
+ $el = $(el)
+ if $el.attr('id') == 'js-shortcuts-home'
+ # Place the logo tooltip on the right when collapsed, bottom when expanded
+ $el.parents('header').hasClass('header-collapsed') and 'right' or 'bottom'
+ else
+ # Otherwise use the data-placement attribute like normal
+ $el.data('placement')
+ })
# Form submitter
$('.trigger-submit').on 'change', ->
diff --git a/app/assets/stylesheets/base/gl_bootstrap.scss b/app/assets/stylesheets/base/gl_bootstrap.scss
index 62a3eade5c7..427f333423c 100644
--- a/app/assets/stylesheets/base/gl_bootstrap.scss
+++ b/app/assets/stylesheets/base/gl_bootstrap.scss
@@ -117,7 +117,7 @@
color: #888;
text-shadow: 0 1px 1px #fff;
}
- i[class~="fa"] {
+ i.fa {
line-height: 14px;
}
}
diff --git a/app/assets/stylesheets/base/mixins.scss b/app/assets/stylesheets/base/mixins.scss
index feff931156c..b8b163a42b2 100644
--- a/app/assets/stylesheets/base/mixins.scss
+++ b/app/assets/stylesheets/base/mixins.scss
@@ -106,7 +106,6 @@
p > code {
font-size: inherit;
font-weight: inherit;
- color: #555;
}
li {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index facd7e19314..97b19deb3ed 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -136,7 +136,7 @@ ul.notes {
display: none;
float: right;
- [class~="fa"] {
+ i.fa {
font-size: 16px;
line-height: 16px;
vertical-align: middle;
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index e9757676908..8f6a766635a 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -39,6 +39,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:sign_in_text,
:home_page_url,
:max_attachment_size,
+ :default_project_visibility,
+ :default_snippet_visibility,
restricted_visibility_levels: []
)
end
diff --git a/app/controllers/import/gitorious_controller.rb b/app/controllers/import/gitorious_controller.rb
index 6067a87ee04..c121d2de7cb 100644
--- a/app/controllers/import/gitorious_controller.rb
+++ b/app/controllers/import/gitorious_controller.rb
@@ -6,7 +6,7 @@ class Import::GitoriousController < Import::BaseController
def callback
session[:gitorious_repos] = params[:repos]
- redirect_to status_import_gitorious_url
+ redirect_to status_import_gitorious_path
end
def status
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 73031851734..dc18bbd8d5b 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -1,12 +1,13 @@
class Projects::ServicesController < Projects::ApplicationController
- ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :subdomain,
+ ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_version, :subdomain,
:room, :recipients, :project_url, :webhook,
:user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
:build_key, :server, :teamcity_url, :build_type,
:description, :issues_url, :new_issue_url, :restrict_to_branch, :channel,
:colorize_messages, :channels,
:push_events, :issues_events, :merge_requests_events, :tag_push_events,
- :note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url]
+ :note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url,
+ :notify, :color]
# Authorize
before_action :authorize_admin_project!
before_action :service, only: [:edit, :update, :test]
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
index 9954617c762..e13d4eaf101 100644
--- a/app/helpers/submodule_helper.rb
+++ b/app/helpers/submodule_helper.rb
@@ -63,7 +63,7 @@ module SubmoduleHelper
namespace = components.pop.gsub(/^\.\.$/, '')
if namespace.empty?
- namespace = @project.group.path
+ namespace = @project.namespace.name
end
[
diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb
index 0d573e72a80..66a1383d61b 100644
--- a/app/helpers/visibility_level_helper.rb
+++ b/app/helpers/visibility_level_helper.rb
@@ -10,7 +10,21 @@ module VisibilityLevelHelper
end
end
- def visibility_level_description(level)
+ # Return the description for the +level+ argument.
+ #
+ # +level+ One of the Gitlab::VisibilityLevel constants
+ # +form_model+ Either a model object (Project, Snippet, etc.) or the name of
+ # a Project or Snippet class.
+ def visibility_level_description(level, form_model)
+ case form_model.is_a?(String) ? form_model : form_model.class.name
+ when 'PersonalSnippet', 'ProjectSnippet', 'Snippet'
+ snippet_visibility_level_description(level)
+ when 'Project'
+ project_visibility_level_description(level)
+ end
+ end
+
+ def project_visibility_level_description(level)
capture_haml do
haml_tag :span do
case level
@@ -64,4 +78,12 @@ module VisibilityLevelHelper
return [] if current_user.is_admin? && !show_all
current_application_settings.restricted_visibility_levels || []
end
+
+ def default_project_visibility
+ current_application_settings.default_project_visibility
+ end
+
+ def default_snippet_visibility
+ current_application_settings.default_snippet_visibility
+ end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 0d8365c4ff2..9406fb91939 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -17,6 +17,8 @@
# twitter_sharing_enabled :boolean default(TRUE)
# restricted_visibility_levels :text
# max_attachment_size :integer default(10)
+# default_project_visibility :integer
+# default_snippet_visibility :integer
#
class ApplicationSetting < ActiveRecord::Base
@@ -51,7 +53,9 @@ class ApplicationSetting < ActiveRecord::Base
gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'],
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
- max_attachment_size: Settings.gitlab['max_attachment_size']
+ max_attachment_size: Settings.gitlab['max_attachment_size'],
+ default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'],
+ default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level']
)
end
diff --git a/app/models/commit_range.rb b/app/models/commit_range.rb
new file mode 100644
index 00000000000..e6456198264
--- /dev/null
+++ b/app/models/commit_range.rb
@@ -0,0 +1,106 @@
+# CommitRange makes it easier to work with commit ranges
+#
+# Examples:
+#
+# range = CommitRange.new('f3f85602...e86e1013')
+# range.exclude_start? # => false
+# range.reference_title # => "Commits f3f85602 through e86e1013"
+# range.to_s # => "f3f85602...e86e1013"
+#
+# range = CommitRange.new('f3f856029bc5f966c5a7ee24cf7efefdd20e6019..e86e1013709735be5bb767e2b228930c543f25ae')
+# range.exclude_start? # => true
+# range.reference_title # => "Commits f3f85602^ through e86e1013"
+# range.to_param # => {from: "f3f856029bc5f966c5a7ee24cf7efefdd20e6019^", to: "e86e1013709735be5bb767e2b228930c543f25ae"}
+# range.to_s # => "f3f85602..e86e1013"
+#
+# # Assuming `project` is a Project with a repository containing both commits:
+# range.project = project
+# range.valid_commits? # => true
+#
+class CommitRange
+ include ActiveModel::Conversion
+
+ attr_reader :sha_from, :notation, :sha_to
+
+ # Optional Project model
+ attr_accessor :project
+
+ # See `exclude_start?`
+ attr_reader :exclude_start
+
+ # The beginning and ending SHA sums can be between 6 and 40 hex characters,
+ # and the range selection can be double- or triple-dot.
+ PATTERN = /\h{6,40}\.{2,3}\h{6,40}/
+
+ # Initialize a CommitRange
+ #
+ # range_string - The String commit range.
+ # project - An optional Project model.
+ #
+ # Raises ArgumentError if `range_string` does not match `PATTERN`.
+ def initialize(range_string, project = nil)
+ range_string.strip!
+
+ unless range_string.match(/\A#{PATTERN}\z/)
+ raise ArgumentError, "invalid CommitRange string format: #{range_string}"
+ end
+
+ @exclude_start = !range_string.include?('...')
+ @sha_from, @notation, @sha_to = range_string.split(/(\.{2,3})/, 2)
+
+ @project = project
+ end
+
+ def inspect
+ %(#<#{self.class}:#{object_id} #{to_s}>)
+ end
+
+ def to_s
+ "#{sha_from[0..7]}#{notation}#{sha_to[0..7]}"
+ end
+
+ # Returns a String for use in a link's title attribute
+ def reference_title
+ "Commits #{suffixed_sha_from} through #{sha_to}"
+ end
+
+ # Return a Hash of parameters for passing to a URL helper
+ #
+ # See `namespace_project_compare_url`
+ def to_param
+ { from: suffixed_sha_from, to: sha_to }
+ end
+
+ def exclude_start?
+ exclude_start
+ end
+
+ # Check if both the starting and ending commit IDs exist in a project's
+ # repository
+ #
+ # project - An optional Project to check (default: `project`)
+ def valid_commits?(project = project)
+ return nil unless project.present?
+ return false unless project.valid_repo?
+
+ commit_from.present? && commit_to.present?
+ end
+
+ def persisted?
+ true
+ end
+
+ def commit_from
+ @commit_from ||= project.repository.commit(suffixed_sha_from)
+ end
+
+ def commit_to
+ @commit_to ||= project.repository.commit(sha_to)
+ end
+
+ private
+
+ def suffixed_sha_from
+ sha_from + (exclude_start? ? '^' : '')
+ end
+end
diff --git a/app/models/project.rb b/app/models/project.rb
index 293ee04f228..397232e98d8 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -686,11 +686,21 @@ class Project < ActiveRecord::Base
end
def create_repository
- if gitlab_shell.add_repository(path_with_namespace)
- true
+ if forked?
+ if gitlab_shell.fork_repository(forked_from_project.path_with_namespace, self.namespace.path)
+ ensure_satellite_exists
+ true
+ else
+ errors.add(:base, 'Failed to fork repository')
+ false
+ end
else
- errors.add(:base, 'Failed to create repository')
- false
+ if gitlab_shell.add_repository(path_with_namespace)
+ true
+ else
+ errors.add(:base, 'Failed to create repository')
+ false
+ end
end
end
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 07520eab5d1..3a15b2207ea 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -20,7 +20,7 @@
class HipchatService < Service
MAX_COMMITS = 3
- prop_accessor :token, :room, :server
+ prop_accessor :token, :room, :server, :notify, :color, :api_version
validates :token, presence: true, if: :activated?
def title
@@ -39,6 +39,10 @@ class HipchatService < Service
[
{ type: 'text', name: 'token', placeholder: 'Room token' },
{ type: 'text', name: 'room', placeholder: 'Room name or ID' },
+ { type: 'checkbox', name: 'notify' },
+ { type: 'select', name: 'color', choices: ['yellow', 'red', 'green', 'purple', 'gray', 'random'] },
+ { type: 'text', name: 'api_version',
+ placeholder: 'Leave blank for default (v2)' },
{ type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://hipchat.example.com' }
]
@@ -52,17 +56,21 @@ class HipchatService < Service
return unless supported_events.include?(data[:object_kind])
message = create_message(data)
return unless message.present?
- gate[room].send('GitLab', message)
+ gate[room].send('GitLab', message, message_options)
end
private
def gate
- options = { api_version: 'v2' }
+ options = { api_version: api_version || 'v2' }
options[:server_url] = server unless server.blank?
@gate ||= HipChat::Client.new(token, options)
end
+ def message_options
+ { notify: notify.present? && notify == '1', color: color || 'yellow' }
+ end
+
def create_message(data)
object_kind = data[:object_kind]
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index a7afcf8f64b..011f6f6145e 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -5,6 +5,8 @@ module Projects
end
def execute
+ forked_from_project_id = params.delete(:forked_from_project_id)
+
@project = Project.new(params)
# Make sure that the user is allowed to use the specified visibility
@@ -45,10 +47,14 @@ module Projects
@project.creator = current_user
+ if forked_from_project_id
+ @project.build_forked_project_link(forked_from_project_id: forked_from_project_id)
+ end
+
Project.transaction do
@project.save
- unless @project.import?
+ if @project.persisted? && !@project.import?
unless @project.create_repository
raise 'Failed to create repository'
end
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 1e4deb6ed39..50f208b11d1 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -1,66 +1,28 @@
module Projects
class ForkService < BaseService
- include Gitlab::ShellAdapter
-
def execute
- @from_project = @project
-
- project_params = {
- visibility_level: @from_project.visibility_level,
- description: @from_project.description,
+ new_params = {
+ forked_from_project_id: @project.id,
+ visibility_level: @project.visibility_level,
+ description: @project.description,
+ name: @project.name,
+ path: @project.path,
+ namespace_id: @params[:namespace].try(:id) || current_user.namespace.id
}
- project = Project.new(project_params)
- project.name = @from_project.name
- project.path = @from_project.path
- project.creator = @current_user
- if @from_project.avatar.present? && @from_project.avatar.image?
- project.avatar = @from_project.avatar
- end
-
- if namespace = @params[:namespace]
- project.namespace = namespace
- else
- project.namespace = @current_user.namespace
+ if @project.avatar.present? && @project.avatar.image?
+ new_params[:avatar] = @project.avatar
end
- unless @current_user.can?(:create_projects, project.namespace)
- project.errors.add(:namespace, 'insufficient access rights')
- return project
- end
-
- # If the project cannot save, we do not want to trigger the project destroy
- # as this can have the side effect of deleting a repo attached to an existing
- # project with the same name and namespace
- if project.valid?
- begin
- Project.transaction do
- #First save the DB entries as they can be rolled back if the repo fork fails
- project.build_forked_project_link(forked_to_project_id: project.id, forked_from_project_id: @from_project.id)
- if project.save
- project.team << [@current_user, :master, @current_user]
- end
-
- #Now fork the repo
- unless gitlab_shell.fork_repository(@from_project.path_with_namespace, project.namespace.path)
- raise 'forking failed in gitlab-shell'
- end
-
- project.ensure_satellite_exists
- end
+ new_project = CreateService.new(current_user, new_params).execute
- if @from_project.gitlab_ci?
- ForkRegistrationWorker.perform_async(@from_project.id, project.id, @current_user.private_token)
- end
- rescue => ex
- project.errors.add(:base, 'Fork transaction failed.')
- project.destroy
+ if new_project.persisted?
+ if @project.gitlab_ci?
+ ForkRegistrationWorker.perform_async(@project.id, new_project.id, @current_user.private_token)
end
- else
- project.errors.add(:base, 'Invalid fork destination')
end
- project
+ new_project
end
end
end
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index 4f3565c67eb..98d3e00153d 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -43,6 +43,14 @@
.col-sm-10
= f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
.form-group
+ = f.label :default_project_visibility, class: 'control-label col-sm-2'
+ .col-sm-10
+ = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: 'Project')
+ .form-group
+ = f.label :default_snippet_visibility, class: 'control-label col-sm-2'
+ .col-sm-10
+ = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: 'Snippet')
+ .form-group
= f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
.col-sm-10
- data_attrs = { toggle: 'buttons' }
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 14996dcd6a2..427f38018b0 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -60,7 +60,7 @@
= form_tag members_update_admin_group_path(@group), id: "new_project_member", class: "bulk_import", method: :put do
%div
- = users_select_tag(:user_ids, multiple: true, email_user: true)
+ = users_select_tag(:user_ids, multiple: true, email_user: true, scope: :all)
%div.prepend-top-10
= select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2"
%hr
diff --git a/app/views/events/event/_created_project.html.haml b/app/views/events/event/_created_project.html.haml
index 552525f4a07..c2577a24982 100644
--- a/app/views/events/event/_created_project.html.haml
+++ b/app/views/events/event/_created_project.html.haml
@@ -18,7 +18,7 @@
%a.twitter-share-button{ |
href: "https://twitter.com/share", |
"data-url" => event.project.web_url, |
- "data-text" => "I just #{event.project.imported? ? "imported" : "created"} a new project in GitLab! GitLab is version control on your server.", |
+ "data-text" => "I just #{event.action_name} a new project on GitLab! GitLab is version control on your server.", |
"data-size" => "medium", |
"data-related" => "gitlab", |
"data-hashtags" => "gitlab", |
diff --git a/app/views/groups/_settings_nav.html.haml b/app/views/groups/_settings_nav.html.haml
index e6aee22e529..f93caf90076 100644
--- a/app/views/groups/_settings_nav.html.haml
+++ b/app/views/groups/_settings_nav.html.haml
@@ -1,11 +1,11 @@
%ul.sidebar-subnav
= nav_link(path: 'groups#edit') do
- = link_to edit_group_path(@group), title: 'Group' do
- %i.fa.fa-pencil-square-o
+ = link_to edit_group_path(@group), title: 'Group', data: {placement: 'right'} do
+ = icon('pencil-square-o')
%span
Group
= nav_link(path: 'groups#projects') do
- = link_to projects_group_path(@group), title: 'Projects' do
- %i.fa.fa-folder
+ = link_to projects_group_path(@group), title: 'Projects', data: {placement: 'right'} do
+ = icon('folder')
%span
Projects
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 0ff1665455e..f72882d883e 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -1,5 +1,6 @@
%head
%meta{charset: "utf-8"}
+ %meta{'http-equiv' => 'X-UA-Compatible', content: 'IE=edge'}
%meta{content: "GitLab Community Edition", name: "description"}
%title
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index 281ce31fe9c..fc4656be079 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -1,49 +1,48 @@
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class }
- .navbar-inner
- .container
+ .container
+ .navbar-inner
%div.app_logo
- = link_to root_path, class: "home has_bottom_tooltip", title: "Dashboard" do
+ = link_to root_path, class: 'home', title: 'Dashboard', id: 'js-shortcuts-home', data: {toggle: 'tooltip', placement: 'bottom'} do
= brand_header_logo
%h3 GitLab
%h1.title= title
- %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
+ %button.navbar-toggle{type: 'button', data: {target: '.navbar-collapse', toggle: 'collapse'}}
%span.sr-only Toggle navigation
- %i.fa.fa-bars
+ = icon('bars')
.navbar-collapse.collapse
%ul.nav.navbar-nav
%li.hidden-sm.hidden-xs
- = render "layouts/search"
+ = render 'layouts/search'
%li.visible-sm.visible-xs
- = link_to search_path, title: "Search", class: 'has_bottom_tooltip', 'data-original-title' => 'Search area' do
- %i.fa.fa-search
+ = link_to search_path, title: 'Search', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = icon('search')
%li
- = link_to help_path, title: 'Help', class: 'has_bottom_tooltip',
- 'data-original-title' => 'Help' do
- %i.fa.fa-question-circle
+ = link_to help_path, title: 'Help', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = icon('question-circle')
%li
- = link_to explore_root_path, title: "Explore", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
- %i.fa.fa-globe
+ = link_to explore_root_path, title: 'Explore', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = icon('globe')
%li
- = link_to user_snippets_path(current_user), title: "Your snippets", class: 'has_bottom_tooltip', 'data-original-title' => 'Your snippets' do
- %i.fa.fa-clipboard
+ = link_to user_snippets_path(current_user), title: 'Your snippets', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = icon('clipboard')
- if current_user.is_admin?
%li
- = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do
- %i.fa.fa-cogs
+ = link_to admin_root_path, title: 'Admin area', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = icon('cogs')
- if current_user.can_create_project?
%li
- = link_to new_project_path, title: "New project", class: 'has_bottom_tooltip', 'data-original-title' => 'New project' do
- %i.fa.fa-plus
+ = link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = icon('plus')
%li
- = link_to profile_path, title: "Profile settings", class: 'has_bottom_tooltip', 'data-original-title' => 'Profile settings"' do
- %i.fa.fa-user
+ = link_to profile_path, title: 'Profile settings', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = icon('user')
%li
- = link_to destroy_user_session_path, class: "logout", method: :delete, title: "Sign out", class: 'has_bottom_tooltip', 'data-original-title' => 'Sign out' do
- %i.fa.fa-sign-out
+ = link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do
+ = icon('sign-out')
%li.hidden-xs
- = link_to current_user, class: "profile-pic has_bottom_tooltip", id: 'profile-pic', 'data-original-title' => 'Your profile' do
+ = link_to current_user, class: 'profile-pic', id: 'profile-pic', data: {toggle: 'tooltip', placement: 'bottom'} do
= image_tag avatar_icon(current_user.email, 60), alt: 'User activity'
= render 'shared/outdated_browser'
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 1c164800b0e..0fa2ec9824d 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -15,7 +15,3 @@
= yield
= yield :embedded_scripts
-
-:coffeescript
- $('.page-sidebar-collapsed .nav-sidebar a').tooltip placement: "right"
-
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index 372fe9a6d36..a3191593dae 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -5,60 +5,60 @@
%span
Overview
= nav_link(controller: :projects) do
- = link_to admin_namespaces_projects_path, title: 'Projects' do
+ = link_to admin_namespaces_projects_path, title: 'Projects', data: {placement: 'right'} do
= icon('cube fw')
%span
Projects
= nav_link(controller: :users) do
- = link_to admin_users_path, title: 'Users' do
+ = link_to admin_users_path, title: 'Users', data: {placement: 'right'} do
= icon('user fw')
%span
Users
= nav_link(controller: :groups) do
- = link_to admin_groups_path, title: 'Groups' do
+ = link_to admin_groups_path, title: 'Groups', data: {placement: 'right'} do
= icon('group fw')
%span
Groups
= nav_link(controller: :deploy_keys) do
- = link_to admin_deploy_keys_path, title: 'Deploy Keys' do
+ = link_to admin_deploy_keys_path, title: 'Deploy Keys', data: {placement: 'right'} do
= icon('key fw')
%span
Deploy Keys
= nav_link(controller: :logs) do
- = link_to admin_logs_path, title: 'Logs' do
+ = link_to admin_logs_path, title: 'Logs', data: {placement: 'right'} do
= icon('file-text fw')
%span
Logs
= nav_link(controller: :broadcast_messages) do
- = link_to admin_broadcast_messages_path, title: 'Broadcast Messages' do
+ = link_to admin_broadcast_messages_path, title: 'Broadcast Messages', data: {placement: 'right'} do
= icon('bullhorn fw')
%span
Messages
= nav_link(controller: :hooks) do
- = link_to admin_hooks_path, title: 'Hooks' do
+ = link_to admin_hooks_path, title: 'Hooks', data: {placement: 'right'} do
= icon('external-link fw')
%span
Hooks
= nav_link(controller: :background_jobs) do
- = link_to admin_background_jobs_path, title: 'Background Jobs' do
+ = link_to admin_background_jobs_path, title: 'Background Jobs', data: {placement: 'right'} do
= icon('cog fw')
%span
Background Jobs
= nav_link(controller: :applications) do
- = link_to admin_applications_path, title: 'Applications' do
+ = link_to admin_applications_path, title: 'Applications', data: {placement: 'right'} do
= icon('cloud fw')
%span
Applications
= nav_link(controller: :services) do
- = link_to admin_application_settings_services_path, title: 'Service Templates' do
+ = link_to admin_application_settings_services_path, title: 'Service Templates', data: {placement: 'right'} do
= icon('copy fw')
%span
Service Templates
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
- = link_to admin_application_settings_path, title: 'Settings' do
+ = link_to admin_application_settings_path, title: 'Settings', data: {placement: 'right'} do
= icon('cogs fw')
%span
Settings
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index c5997e44370..d46dba4a240 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -1,38 +1,38 @@
%ul.nav.nav-sidebar
= nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
- = link_to root_path, title: 'Home', class: 'shortcuts-activity' do
+ = link_to root_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
= icon('dashboard fw')
%span
Your Projects
= nav_link(path: 'projects#starred') do
- = link_to starred_dashboard_projects_path, title: 'Starred Projects' do
+ = link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
= icon('star fw')
%span
Starred Projects
= nav_link(controller: :groups) do
- = link_to dashboard_groups_path, title: 'Groups' do
+ = link_to dashboard_groups_path, title: 'Groups', data: {placement: 'right'} do
= icon('group fw')
%span
Groups
= nav_link(controller: :milestones) do
- = link_to dashboard_milestones_path, title: 'Milestones' do
+ = link_to dashboard_milestones_path, title: 'Milestones', data: {placement: 'right'} do
= icon('clock-o fw')
%span
Milestones
= nav_link(path: 'dashboard#issues') do
- = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
+ = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues', data: {placement: 'right'} do
= icon('exclamation-circle fw')
%span
Issues
%span.count= current_user.assigned_issues.opened.count
= nav_link(path: 'dashboard#merge_requests') do
- = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests' do
+ = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests', data: {placement: 'right'} do
= icon('tasks fw')
%span
Merge Requests
%span.count= current_user.assigned_merge_requests.opened.count
= nav_link(controller: :help) do
- = link_to help_path, title: 'Help' do
+ = link_to help_path, title: 'Help', data: {placement: 'right'} do
= icon('question-circle fw')
%span
Help
diff --git a/app/views/layouts/nav/_explore.html.haml b/app/views/layouts/nav/_explore.html.haml
index 38d84cd9b51..66870e84ceb 100644
--- a/app/views/layouts/nav/_explore.html.haml
+++ b/app/views/layouts/nav/_explore.html.haml
@@ -1,18 +1,18 @@
%ul.nav.nav-sidebar
= nav_link(path: 'projects#trending') do
- = link_to explore_root_path do
+ = link_to explore_root_path, title: 'Trending Projects', data: {placement: 'right'} do
= icon('comments fw')
%span Trending Projects
= nav_link(path: 'projects#starred') do
- = link_to starred_explore_projects_path do
+ = link_to starred_explore_projects_path, title: 'Most-starred Projects', data: {placement: 'right'} do
= icon('star fw')
- %span Most Starred Projects
+ %span Most-starred Projects
= nav_link(path: 'projects#index') do
- = link_to explore_projects_path do
+ = link_to explore_projects_path, title: 'All Projects', data: {placement: 'right'} do
= icon('bookmark fw')
%span All Projects
= nav_link(controller: :groups) do
- = link_to explore_groups_path do
+ = link_to explore_groups_path, title: 'All Groups', data: {placement: 'right'} do
= icon('group fw')
%span All Groups
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index 7cce9ffe3d5..74a8526dbd7 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -1,38 +1,38 @@
%ul.nav.nav-sidebar
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
- = link_to group_path(@group), title: "Home" do
+ = link_to group_path(@group), title: 'Home', data: {placement: 'right'} do
= icon('dashboard fw')
%span
Activity
- if current_user
= nav_link(controller: [:group, :milestones]) do
- = link_to group_milestones_path(@group), title: 'Milestones' do
+ = link_to group_milestones_path(@group), title: 'Milestones', data: {placement: 'right'} do
= icon('clock-o fw')
%span
Milestones
= nav_link(path: 'groups#issues') do
- = link_to issues_group_path(@group), title: 'Issues' do
+ = link_to issues_group_path(@group), title: 'Issues', data: {placement: 'right'} do
= icon('exclamation-circle fw')
%span
Issues
- if current_user
%span.count= Issue.opened.of_group(@group).count
= nav_link(path: 'groups#merge_requests') do
- = link_to merge_requests_group_path(@group), title: 'Merge Requests' do
+ = link_to merge_requests_group_path(@group), title: 'Merge Requests', data: {placement: 'right'} do
= icon('tasks fw')
%span
Merge Requests
- if current_user
%span.count= MergeRequest.opened.of_group(@group).count
= nav_link(controller: [:group_members]) do
- = link_to group_group_members_path(@group), title: 'Members' do
+ = link_to group_group_members_path(@group), title: 'Members', data: {placement: 'right'} do
= icon('users fw')
%span
Members
- if can?(current_user, :admin_group, @group)
= nav_link(html_options: { class: "#{"active" if group_settings_page?} separate-item" }) do
- = link_to edit_group_path(@group), title: 'Settings', class: "tab no-highlight" do
+ = link_to edit_group_path(@group), title: 'Settings', class: 'tab no-highlight', data: {placement: 'right'} do
= icon ('cogs fw')
%span
Settings
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index 9f2932c79cd..31d8ed3ed86 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -1,50 +1,50 @@
%ul.nav.nav-sidebar
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
- = link_to profile_path, title: "Profile" do
+ = link_to profile_path, title: 'Profile', data: {placement: 'right'} do
= icon('user fw')
%span
Profile
= nav_link(controller: :accounts) do
- = link_to profile_account_path, title: 'Account' do
+ = link_to profile_account_path, title: 'Account', data: {placement: 'right'} do
= icon('gear fw')
%span
Account
= nav_link(path: ['profiles#applications', 'applications#edit', 'applications#show', 'applications#new']) do
- = link_to applications_profile_path, title: 'Applications' do
+ = link_to applications_profile_path, title: 'Applications', data: {placement: 'right'} do
= icon('cloud fw')
%span
Applications
= nav_link(controller: :emails) do
- = link_to profile_emails_path, title: 'Emails' do
+ = link_to profile_emails_path, title: 'Emails', data: {placement: 'right'} do
= icon('envelope-o fw')
%span
Emails
%span.count= current_user.emails.count + 1
- unless current_user.ldap_user?
= nav_link(controller: :passwords) do
- = link_to edit_profile_password_path, title: 'Password' do
+ = link_to edit_profile_password_path, title: 'Password', data: {placement: 'right'} do
= icon('lock fw')
%span
Password
= nav_link(controller: :notifications) do
- = link_to profile_notifications_path, title: 'Notifications' do
+ = link_to profile_notifications_path, title: 'Notifications', data: {placement: 'right'} do
= icon('inbox fw')
%span
Notifications
= nav_link(controller: :keys) do
- = link_to profile_keys_path, title: 'SSH Keys' do
+ = link_to profile_keys_path, title: 'SSH Keys', data: {placement: 'right'} do
= icon('key fw')
%span
SSH Keys
%span.count= current_user.keys.count
= nav_link(path: 'profiles#design') do
- = link_to design_profile_path, title: 'Design' do
+ = link_to design_profile_path, title: 'Design', data: {placement: 'right'} do
= icon('image fw')
%span
Design
= nav_link(path: 'profiles#history') do
- = link_to history_profile_path, title: 'History' do
+ = link_to history_profile_path, title: 'History', data: {placement: 'right'} do
= icon('history fw')
%span
History
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index a2a9d8a340b..01b3d70194f 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -1,7 +1,7 @@
%ul.project-navigation.nav.nav-sidebar
- if @project_settings_nav
= nav_link do
- = link_to project_path(@project), title: 'Back to project', class: "" do
+ = link_to project_path(@project), title: 'Back to project', data: {placement: 'right'} do
= icon('caret-square-o-left fw')
%span
Back to project
@@ -11,49 +11,49 @@
= render 'projects/settings_nav'
- else
- = nav_link(path: 'projects#show', html_options: {class: "home"}) do
- = link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
+ = nav_link(path: 'projects#show', html_options: {class: 'home'}) do
+ = link_to project_path(@project), title: 'Project', class: 'shortcuts-project', data: {placement: 'right'} do
= icon('dashboard fw')
%span
Project
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
- = link_to namespace_project_tree_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Files', class: 'shortcuts-tree' do
+ = link_to namespace_project_tree_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Files', class: 'shortcuts-tree', data: {placement: 'right'} do
= icon('files-o fw')
%span
Files
- if project_nav_tab? :commits
= nav_link(controller: %w(commit commits compare repositories tags branches)) do
- = link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Commits', class: 'shortcuts-commits' do
+ = link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Commits', class: 'shortcuts-commits', data: {placement: 'right'} do
= icon('history fw')
%span
Commits
- if project_nav_tab? :network
= nav_link(controller: %w(network)) do
- = link_to namespace_project_network_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Network', class: 'shortcuts-network' do
+ = link_to namespace_project_network_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Network', class: 'shortcuts-network', data: {placement: 'right'} do
= icon('code-fork fw')
%span
Network
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
- = link_to namespace_project_graph_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Graphs', class: 'shortcuts-graphs' do
+ = link_to namespace_project_graph_path(@project.namespace, @project, @ref || @repository.root_ref), title: 'Graphs', class: 'shortcuts-graphs', data: {placement: 'right'} do
= icon('area-chart fw')
%span
Graphs
- if project_nav_tab? :milestones
= nav_link(controller: :milestones) do
- = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
+ = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones', data: {placement: 'right'} do
= icon('clock-o fw')
%span
Milestones
- if project_nav_tab? :issues
= nav_link(controller: :issues) do
- = link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
+ = link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues', data: {placement: 'right'} do
= icon('exclamation-circle fw')
%span
Issues
@@ -62,7 +62,7 @@
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
- = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
+ = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests', data: {placement: 'right'} do
= icon('tasks fw')
%span
Merge Requests
@@ -70,28 +70,28 @@
- if project_nav_tab? :labels
= nav_link(controller: :labels) do
- = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
+ = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels', data: {placement: 'right'} do
= icon('tags fw')
%span
Labels
- if project_nav_tab? :wiki
= nav_link(controller: :wikis) do
- = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
+ = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki', data: {placement: 'right'} do
= icon('book fw')
%span
Wiki
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
- = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
+ = link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets', data: {placement: 'right'} do
= icon('file-text-o fw')
%span
Snippets
- if project_nav_tab? :settings
= nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
- = link_to edit_project_path(@project), title: 'Settings', class: "stat-tab tab no-highlight" do
+ = link_to edit_project_path(@project), title: 'Settings', class: 'stat-tab tab no-highlight', data: {placement: 'right'} do
= icon('cogs fw')
%span
Settings
diff --git a/app/views/layouts/nav/_snippets.html.haml b/app/views/layouts/nav/_snippets.html.haml
index edd05f2dd81..0de3a9e5bb7 100644
--- a/app/views/layouts/nav/_snippets.html.haml
+++ b/app/views/layouts/nav/_snippets.html.haml
@@ -1,11 +1,11 @@
%ul.nav.nav-sidebar
= nav_link(path: user_snippets_path(current_user), html_options: {class: 'home'}) do
- = link_to user_snippets_path(current_user), title: 'Your snippets' do
+ = link_to user_snippets_path(current_user), title: 'Your snippets', data: {placement: 'right'} do
= icon('dashboard fw')
%span
Your Snippets
= nav_link(path: snippets_path) do
- = link_to snippets_path, title: 'Discover snippets' do
+ = link_to snippets_path, title: 'Discover snippets', data: {placement: 'right'} do
= icon('globe fw')
%span
Discover Snippets
diff --git a/app/views/profiles/update.js.erb b/app/views/profiles/update.js.erb
index e664ac2a52a..db37619136d 100644
--- a/app/views/profiles/update.js.erb
+++ b/app/views/profiles/update.js.erb
@@ -1,9 +1,3 @@
// Remove body class for any previous theme, re-add current one
-$('body').removeClass('ui_basic ui_mars ui_modern ui_gray ui_color light_theme dark_theme')
+$('body').removeClass('<%= Gitlab::Theme.body_classes %>')
$('body').addClass('<%= app_theme %> <%= theme_type %>')
-
-// Re-render the header to reflect the new theme
-$('header').html('<%= escape_javascript(render("layouts/head_panel", title: "Profile")) %>')
-
-// Re-initialize header tooltips
-$('.has_bottom_tooltip').tooltip({placement: 'bottom'})
diff --git a/app/views/projects/_settings_nav.html.haml b/app/views/projects/_settings_nav.html.haml
index 281a84a3d3c..f8b74809b76 100644
--- a/app/views/projects/_settings_nav.html.haml
+++ b/app/views/projects/_settings_nav.html.haml
@@ -1,31 +1,31 @@
%ul.project-settings-nav.sidebar-subnav
= nav_link(path: 'projects#edit') do
- = link_to edit_project_path(@project), title: 'Project', class: "stat-tab tab " do
- %i.fa.fa-pencil-square-o
+ = link_to edit_project_path(@project), title: 'Project', class: 'stat-tab tab', data: {placement: 'right'} do
+ = icon('pencil-square-o')
%span
Project
= nav_link(controller: [:project_members, :teams]) do
- = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: "team-tab tab" do
- %i.fa.fa-users
+ = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab', data: {placement: 'right'} do
+ = icon('users')
%span
Members
= nav_link(controller: :deploy_keys) do
- = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do
- %i.fa.fa-key
+ = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys', data: {placement: 'right'} do
+ = icon('key')
%span
Deploy Keys
= nav_link(controller: :hooks) do
- = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Web Hooks' do
- %i.fa.fa-link
+ = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Web Hooks', data: {placement: 'right'} do
+ = icon('link')
%span
Web Hooks
= nav_link(controller: :services) do
- = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do
- %i.fa.fa-cogs
+ = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services', data: {placement: 'right'} do
+ = icon('cogs')
%span
Services
= nav_link(controller: :protected_branches) do
- = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do
- %i.fa.fa-lock
+ = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches', data: {placement: 'right'} do
+ = icon('lock')
%span
Protected branches
diff --git a/app/views/projects/_visibility_level.html.haml b/app/views/projects/_visibility_level.html.haml
deleted file mode 100644
index 42c8e685224..00000000000
--- a/app/views/projects/_visibility_level.html.haml
+++ /dev/null
@@ -1,27 +0,0 @@
-.form-group.project-visibility-level-holder
- = f.label :visibility_level, class: 'control-label' do
- Visibility Level
- = link_to "(?)", help_page_path("public_access", "public_access")
- .col-sm-10
- - if can_change_visibility_level
- - Gitlab::VisibilityLevel.values.each do |level|
- .radio
- - restricted = restricted_visibility_levels.include?(level)
- = label :project_visibility_level, level do
- = f.radio_button :visibility_level, level, checked: (visibility_level == level), disabled: restricted
- = visibility_level_icon(level)
- .option-title
- = visibility_level_label(level)
- .option-descr
- = visibility_level_description(level)
- - unless restricted_visibility_levels.empty?
- .col-sm-10
- %span.info
- Some visibility level settings have been restricted by the administrator.
- - else
- .col-sm-10
- %span.info
- = visibility_level_icon(visibility_level)
- %strong
- = visibility_level_label(visibility_level)
- .light= visibility_level_description(visibility_level)
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index fbf04847e48..c09d794ef7f 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -29,7 +29,7 @@
.col-sm-10= f.select(:default_branch, @repository.branch_names, {}, {class: 'select2 select-wide'})
- = render "visibility_level", f: f, visibility_level: @project.visibility_level, can_change_visibility_level: can?(current_user, :change_visibility_level, @project)
+ = render 'shared/visibility_level', f: f, visibility_level: @project.visibility_level, can_change_visibility_level: can?(current_user, :change_visibility_level, @project), form_model: @project
.form-group
= f.label :tag_list, "Tags", class: 'control-label'
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index a06c85b4251..47c69f89a97 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -93,7 +93,7 @@
%span.light (optional)
.col-sm-10
= f.text_area :description, placeholder: "Awesome project", class: "form-control", rows: 3, maxlength: 250, tabindex: 3
- = render "visibility_level", f: f, visibility_level: gitlab_config.default_projects_features.visibility_level, can_change_visibility_level: true
+ = render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project
.form-actions
= f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
diff --git a/app/views/projects/snippets/edit.html.haml b/app/views/projects/snippets/edit.html.haml
index 2d4d5d030ab..7baddebde45 100644
--- a/app/views/projects/snippets/edit.html.haml
+++ b/app/views/projects/snippets/edit.html.haml
@@ -1,4 +1,4 @@
%h3.page-title
Edit snippet
%hr
-= render "shared/snippets/form", url: namespace_project_snippet_path(@project.namespace, @project, @snippet)
+= render "shared/snippets/form", url: namespace_project_snippet_path(@project.namespace, @project, @snippet), visibility_level: @snippet.visibility_level
diff --git a/app/views/projects/snippets/new.html.haml b/app/views/projects/snippets/new.html.haml
index bb659dba0cf..5efe662665e 100644
--- a/app/views/projects/snippets/new.html.haml
+++ b/app/views/projects/snippets/new.html.haml
@@ -1,4 +1,4 @@
%h3.page-title
New snippet
%hr
-= render "shared/snippets/form", url: namespace_project_snippets_path(@project.namespace, @project, @snippet)
+= render "shared/snippets/form", url: namespace_project_snippets_path(@project.namespace, @project, @snippet), visibility_level: default_snippet_visibility
diff --git a/app/views/shared/_visibility_level.html.haml b/app/views/shared/_visibility_level.html.haml
new file mode 100644
index 00000000000..1c6ec198d3d
--- /dev/null
+++ b/app/views/shared/_visibility_level.html.haml
@@ -0,0 +1,14 @@
+.form-group.project-visibility-level-holder
+ = f.label :visibility_level, class: 'control-label' do
+ Visibility Level
+ = link_to "(?)", help_page_path("public_access", "public_access")
+ .col-sm-10
+ - if can_change_visibility_level
+ = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
+ - else
+ .col-sm-10
+ %span.info
+ = visibility_level_icon(visibility_level)
+ %strong
+ = visibility_level_label(visibility_level)
+ .light= visibility_level_description(visibility_level, form_model)
diff --git a/app/views/shared/_visibility_radios.html.haml b/app/views/shared/_visibility_radios.html.haml
new file mode 100644
index 00000000000..b07c4d20f12
--- /dev/null
+++ b/app/views/shared/_visibility_radios.html.haml
@@ -0,0 +1,14 @@
+- Gitlab::VisibilityLevel.values.each do |level|
+ .radio
+ - restricted = restricted_visibility_levels.include?(level)
+ = label model_method, level do
+ = form.radio_button model_method, level, checked: (selected_level == level), disabled: restricted
+ = visibility_level_icon(level)
+ .option-title
+ = visibility_level_label(level)
+ .option-descr
+ = visibility_level_description(level, form_model)
+- unless restricted_visibility_levels.empty?
+ .col-sm-10
+ %span.info
+ Some visibility level settings have been restricted by the administrator.
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index 4e0663ea208..6783587bda9 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -10,7 +10,7 @@
= f.label :title, class: 'control-label'
.col-sm-10= f.text_field :title, placeholder: "Example Snippet", class: 'form-control', required: true
- = render "shared/snippets/visibility_level", f: f, visibility_level: gitlab_config.default_projects_features.visibility_level, can_change_visibility_level: true
+ = render 'shared/visibility_level', f: f, visibility_level: visibility_level, can_change_visibility_level: true, form_model: @snippet
.form-group
.file-editor
diff --git a/app/views/shared/snippets/_visibility_level.html.haml b/app/views/shared/snippets/_visibility_level.html.haml
deleted file mode 100644
index 9acff18e450..00000000000
--- a/app/views/shared/snippets/_visibility_level.html.haml
+++ /dev/null
@@ -1,27 +0,0 @@
-.form-group.project-visibility-level-holder
- = f.label :visibility_level, class: 'control-label' do
- Visibility Level
- = link_to "(?)", help_page_path("public_access", "public_access")
- .col-sm-10
- - if can_change_visibility_level
- - Gitlab::VisibilityLevel.values.each do |level|
- .radio
- - restricted = restricted_visibility_levels.include?(level)
- = f.radio_button :visibility_level, level, disabled: restricted
- = label "#{dom_class(@snippet)}_visibility_level", level do
- = visibility_level_icon(level)
- .option-title
- = visibility_level_label(level)
- .option-descr
- = snippet_visibility_level_description(level)
- - unless restricted_visibility_levels.empty?
- .col-sm-10
- %span.info
- Some visibility level settings have been restricted by the administrator.
- - else
- .col-sm-10
- %span.info
- = visibility_level_icon(visibility_level)
- %strong
- = visibility_level_label(visibility_level)
- .light= visibility_level_description(visibility_level)
diff --git a/app/views/snippets/edit.html.haml b/app/views/snippets/edit.html.haml
index 7042d07d5e8..30aa174edfb 100644
--- a/app/views/snippets/edit.html.haml
+++ b/app/views/snippets/edit.html.haml
@@ -1,4 +1,4 @@
%h3.page-title
Edit snippet
%hr
-= render "shared/snippets/form", url: snippet_path(@snippet)
+= render 'shared/snippets/form', url: snippet_path(@snippet), visibility_level: @snippet.visibility_level
diff --git a/app/views/snippets/new.html.haml b/app/views/snippets/new.html.haml
index 694d7058317..77cfd9af335 100644
--- a/app/views/snippets/new.html.haml
+++ b/app/views/snippets/new.html.haml
@@ -1,4 +1,4 @@
%h3.page-title
New snippet
%hr
-= render "shared/snippets/form", url: snippets_path(@snippet)
+= render "shared/snippets/form", url: snippets_path(@snippet), visibility_level: default_snippet_visibility
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index ba40671b162..93a01c0723f 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -76,7 +76,6 @@ production: &base
merge_requests: true
wiki: true
snippets: false
- visibility_level: "private" # can be "private" | "internal" | "public"
## Webhook settings
# Number of seconds to wait for HTTP response after sending webhook HTTP POST request (default: 10)
diff --git a/db/migrate/20150423033240_add_default_project_visibililty_to_application_settings.rb b/db/migrate/20150423033240_add_default_project_visibililty_to_application_settings.rb
new file mode 100644
index 00000000000..9b0f13f3fa7
--- /dev/null
+++ b/db/migrate/20150423033240_add_default_project_visibililty_to_application_settings.rb
@@ -0,0 +1,7 @@
+class AddDefaultProjectVisibililtyToApplicationSettings < ActiveRecord::Migration
+ def change
+ add_column :application_settings, :default_project_visibility, :integer
+ visibility = Settings.gitlab.default_projects_features['visibility_level']
+ execute("update application_settings set default_project_visibility = #{visibility}")
+ end
+end
diff --git a/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb b/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb
new file mode 100644
index 00000000000..51237354d9f
--- /dev/null
+++ b/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb
@@ -0,0 +1,7 @@
+class AddDefaultSnippetVisibilityToAppSettings < ActiveRecord::Migration
+ def change
+ add_column :application_settings, :default_snippet_visibility, :integer
+ visibility = Settings.gitlab.default_projects_features['visibility_level']
+ execute("update application_settings set default_snippet_visibility = #{visibility}")
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 6db7e386c86..8683c0446fe 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20150421120000) do
+ActiveRecord::Schema.define(version: 20150425173433) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -29,6 +29,8 @@ ActiveRecord::Schema.define(version: 20150421120000) do
t.boolean "twitter_sharing_enabled", default: true
t.text "restricted_visibility_levels"
t.integer "max_attachment_size", default: 10, null: false
+ t.integer "default_project_visibility"
+ t.integer "default_snippet_visibility"
end
create_table "broadcast_messages", force: true do |t|
@@ -470,6 +472,7 @@ ActiveRecord::Schema.define(version: 20150421120000) do
t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at"
t.integer "created_by_id"
+ t.datetime "last_credential_check_at"
t.string "avatar"
t.string "confirmation_token"
t.datetime "confirmed_at"
@@ -477,7 +480,6 @@ ActiveRecord::Schema.define(version: 20150421120000) do
t.string "unconfirmed_email"
t.boolean "hide_no_ssh_key", default: false
t.string "website_url", default: "", null: false
- t.datetime "last_credential_check_at"
t.string "github_access_token"
t.string "gitlab_access_token"
t.string "notification_email"
diff --git a/doc/integration/gitlab_buttons_in_gmail.md b/doc/integration/gitlab_buttons_in_gmail.md
index a9885cef109..e35bb8ba693 100644
--- a/doc/integration/gitlab_buttons_in_gmail.md
+++ b/doc/integration/gitlab_buttons_in_gmail.md
@@ -7,11 +7,11 @@ If correctly setup, emails that require an action will be marked in Gmail.
![gitlab_actions](gitlab_actions.png)
To get this functioning, you need to be registered with Google.
-[See how to register with google in this document.](https://developers.google.com/gmail/markup/registering-with-google)
+[See how to register with Google in this document.](https://developers.google.com/gmail/markup/registering-with-google)
-To aid the registering with google, GitLab offers a rake task that will send an email to google whitelisting email address from your GitLab server.
+To aid the registering with Google, GitLab offers a rake task that will send an email to Google whitelisting email address from your GitLab server.
-To check what would be sent to the google email address, run the rake task:
+To check what would be sent to the Google email address, run the rake task:
```bash
bundle exec rake gitlab:mail_google_schema_whitelisting RAILS_ENV=production
@@ -19,7 +19,7 @@ bundle exec rake gitlab:mail_google_schema_whitelisting RAILS_ENV=production
**This will not send the email but give you the output of how the mail will look.**
-Copy the output of the rake task to [google email markup tester](https://www.google.com/webmasters/markup-tester/u/0/) and press "Validate".
+Copy the output of the rake task to [Google email markup tester](https://www.google.com/webmasters/markup-tester/u/0/) and press "Validate".
If you receive "No errors detected" message from the tester you can send the email using:
diff --git a/docker/Dockerfile b/docker/Dockerfile
index bb25bb677ca..69e34955b7f 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -11,7 +11,7 @@ RUN apt-get update -q \
# If the Omnibus package version below is outdated please contribute a merge request to update it.
# If you run GitLab Enterprise Edition point it to a location where you have downloaded it.
RUN TMP_FILE=$(mktemp); \
- wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.9.2-omnibus-1_amd64.deb \
+ wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab-ce_7.10.0~omnibus.2-1_amd64.deb \
&& dpkg -i $TMP_FILE \
&& rm -f $TMP_FILE
diff --git a/docker/README.md b/docker/README.md
index b7e8b0db7e7..a54739ae3d3 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -3,16 +3,19 @@ What is GitLab?
GitLab offers git repository management, code reviews, issue tracking, activity feeds, wikis. It has LDAP/AD integration, handles 25,000 users on a single server but can also run on a highly available active/active cluster. A subscription gives you access to our support team and to GitLab Enterprise Edition that contains extra features aimed at larger organizations.
-<https://about.gitlab.com>
+Learn more on [https://about.gitlab.com](https://about.gitlab.com)
-![GitLab Logo](https://gitlab.com/uploads/appearance/logo/1/brand_logo-c37eb221b456bb4b472cc1084480991f.png)
-
-How to use these images
+How to build and use images yourself
======================
-At this moment GitLab doesn't have official Docker images. For convinience we will use suffix _xy where xy is current version of GitLab.
-Build your own based on the Omnibus packages with the following commands (it assumes you're in the GitLab repo root directory):
+At this moment GitLab doesn't have official Docker images.
+There are unofficial images at the bottom of this document.
+But in this section we'll build our own.
+For convinience we will use suffix _xy where xy is current version of GitLab.
+Build your own based on the Omnibus packages with the following commands.
+Run these from the GitLab repo root directory.
+People using boot2docker should run it without sudo.
```bash
sudo docker build --tag gitlab_data_image docker/data/
@@ -42,11 +45,11 @@ sudo docker run --detach --name gitlab_app_xy --publish 8080:80 --publish 2222:2
It might take a while before the docker container is responding to queries. You can follow the configuration process with `sudo docker logs -f gitlab_app_xy`.
-You can then go to `http://localhost:8080/` (or `http://192.168.59.103:8080/` if you use boot2docker).
+You can then go to [http://localhost:8080/](http://localhost:8080/) or [http://192.168.59.103:8080/](http://192.168.59.103:8080/) if you use boot2docker.
+
You can login with username `root` and password `5iveL!fe`.
Next time, you can just use `sudo docker start gitlab_app` and `sudo docker stop gitlab_app`.
-
How to configure GitLab
========================
@@ -55,7 +58,7 @@ This container uses the official Omnibus GitLab distribution, so all configurati
To access GitLab configuration, you can start an interactive command line in a new container using the shared data volume container, you will be able to browse the 3 directories and use your favorite text editor:
```bash
-sudo docker run -ti -e TERM=linux --rm --volumes-from gitlab_data ubuntu
+sudo docker run -ti -e TERM=linux --rm --volumes-from gitlab_data ubuntu
vi /etc/gitlab/gitlab.rb
```
@@ -86,3 +89,26 @@ sudo docker rmi gitlab_app_image_78
Troubleshooting
=========================
Please see the [troubleshooting](troubleshooting.md) file in this directory.
+
+
+Publish the images to Dockerhub
+=========================
+Login to Dockerhub with `sudo docker login` and run the following (replace '7.9.2' with the version you're using and 'Sytse Sijbrandij' with your name):
+
+```bash
+sudo docker commit -m "Initial commit" -a "Sytse Sijbrandij" gitlab_app_xy sytse/gitlab-ce:7.9.2
+sudo docker push sytse/gitlab-ce:7.9.2
+sudo docker commit -m "Initial commit" -a "Sytse Sijbrandij" gitlab_data sytse/gitlab_data
+sudo docker push sytse/gitlab_data
+```
+
+Use images published to Dockerhub
+================================
+This examples uses the unofficial images made by GitLab CEO Sytse.
+
+```bash
+sudo docker pull sytse/gitlab_data
+sudo docker pull sytse/gitlab-ce:7.9.2
+sudo docker run --name gitlab_data_volume sytse/gitlab_data /bin/true
+sudo docker run --detach --name gitlab_app_7_9_2 --publish 8080:80 --publish 2222:22 --volumes-from gitlab_data_volume sytse/gitlab-ce:7.9.2
+```
diff --git a/features/steps/dashboard/new_project.rb b/features/steps/dashboard/new_project.rb
index 5e588ceb780..93456a81ecf 100644
--- a/features/steps/dashboard/new_project.rb
+++ b/features/steps/dashboard/new_project.rb
@@ -4,7 +4,9 @@ class Spinach::Features::NewProject < Spinach::FeatureSteps
include SharedProject
step 'I click "New project" link' do
- click_link "New project"
+ within('.content') do
+ click_link "New project"
+ end
end
step 'I see "New project" page' do
diff --git a/features/support/capybara.rb b/features/support/capybara.rb
new file mode 100644
index 00000000000..31dbf0feb2f
--- /dev/null
+++ b/features/support/capybara.rb
@@ -0,0 +1,24 @@
+require 'spinach/capybara'
+require 'capybara/poltergeist'
+
+# Give CI some extra time
+timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 90 : 10
+
+Capybara.javascript_driver = :poltergeist
+Capybara.register_driver :poltergeist do |app|
+ Capybara::Poltergeist::Driver.new(app, js_errors: true, timeout: timeout)
+end
+
+Spinach.hooks.on_tag("javascript") do
+ Capybara.current_driver = Capybara.javascript_driver
+end
+
+Capybara.default_wait_time = timeout
+Capybara.ignore_hidden_elements = false
+
+unless ENV['CI'] || ENV['CI_SERVER']
+ require 'capybara-screenshot/spinach'
+
+ # Keep only the screenshots generated from the last failing test suite
+ Capybara::Screenshot.prune_strategy = :keep_last_run
+end
diff --git a/features/support/db_cleaner.rb b/features/support/db_cleaner.rb
new file mode 100644
index 00000000000..1ab308cfa55
--- /dev/null
+++ b/features/support/db_cleaner.rb
@@ -0,0 +1,11 @@
+require 'database_cleaner'
+
+DatabaseCleaner.strategy = :truncation
+
+Spinach.hooks.before_scenario do
+ DatabaseCleaner.start
+end
+
+Spinach.hooks.after_scenario do
+ DatabaseCleaner.clean
+end
diff --git a/features/support/env.rb b/features/support/env.rb
index be17065ccfd..f34302721ed 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -11,40 +11,18 @@ ENV['RAILS_ENV'] = 'test'
require './config/environment'
require 'rspec'
require 'rspec/expectations'
-require 'database_cleaner'
-require 'spinach/capybara'
require 'sidekiq/testing/inline'
+require_relative 'capybara'
+require_relative 'db_cleaner'
+
%w(select2_helper test_env repo_helpers).each do |f|
require Rails.root.join('spec', 'support', f)
end
-Dir["#{Rails.root}/features/steps/shared/*.rb"].each {|file| require file}
+Dir["#{Rails.root}/features/steps/shared/*.rb"].each { |file| require file }
WebMock.allow_net_connect!
-#
-# JS driver
-#
-require 'capybara/poltergeist'
-Capybara.javascript_driver = :poltergeist
-Capybara.register_driver :poltergeist do |app|
- Capybara::Poltergeist::Driver.new(app, js_errors: false, timeout: 90)
-end
-Spinach.hooks.on_tag("javascript") do
- ::Capybara.current_driver = ::Capybara.javascript_driver
-end
-Capybara.default_wait_time = 60
-Capybara.ignore_hidden_elements = false
-
-DatabaseCleaner.strategy = :truncation
-
-Spinach.hooks.before_scenario do
- DatabaseCleaner.start
-end
-
-Spinach.hooks.after_scenario do
- DatabaseCleaner.clean
-end
Spinach.hooks.before_run do
include RSpec::Mocks::ExampleMethods
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 3fd0823df06..45bb904ed7a 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -17,7 +17,7 @@ module Gitlab
events = Event.reorder(nil).contributions.where(author_id: user.id).
where("created_at > ?", date_from).where(project_id: projects).
group('date(created_at)').
- select('date(created_at), count(id) as total_amount').
+ select('date(created_at) as date, count(id) as total_amount').
map(&:attributes)
dates = (1.year.ago.to_date..(Date.today + 1.day)).to_a
diff --git a/lib/gitlab/gitorious_import/client.rb b/lib/gitlab/gitorious_import/client.rb
index 8cdc3d4afae..1fa89dba448 100644
--- a/lib/gitlab/gitorious_import/client.rb
+++ b/lib/gitlab/gitorious_import/client.rb
@@ -14,7 +14,7 @@ module Gitlab
end
def repos
- @repos ||= repo_names.map { |full_name| Repository.new(full_name) }
+ @repos ||= repo_names.map { |full_name| GitoriousImport::Repository.new(full_name) }
end
def repo(id)
diff --git a/lib/gitlab/markdown/commit_range_reference_filter.rb b/lib/gitlab/markdown/commit_range_reference_filter.rb
index baa97bee9bf..8764f7e474f 100644
--- a/lib/gitlab/markdown/commit_range_reference_filter.rb
+++ b/lib/gitlab/markdown/commit_range_reference_filter.rb
@@ -32,11 +32,8 @@ module Gitlab
# Pattern used to extract commit range references from text
#
- # The beginning and ending SHA1 sums can be between 6 and 40 hex
- # characters, and the range selection can be double- or triple-dot.
- #
# This pattern supports cross-project references.
- COMMIT_RANGE_PATTERN = /(#{PROJECT_PATTERN}@)?(?<commit_range>\h{6,40}\.{2,3}\h{6,40})/
+ COMMIT_RANGE_PATTERN = /(#{PROJECT_PATTERN}@)?(?<commit_range>#{CommitRange::PATTERN})/
def call
replace_text_nodes_matching(COMMIT_RANGE_PATTERN) do |content|
@@ -53,52 +50,34 @@ module Gitlab
# links have `gfm` and `gfm-commit_range` class names attached for
# styling.
def commit_range_link_filter(text)
- self.class.references_in(text) do |match, commit_range, project_ref|
+ self.class.references_in(text) do |match, id, project_ref|
project = self.project_from_ref(project_ref)
- from_id, to_id = split_commit_range(commit_range)
+ range = CommitRange.new(id, project)
+
+ if range.valid_commits?
+ push_result(:commit_range, range)
- if valid_range?(project, from_id, to_id)
- url = url_for_commit_range(project, from_id, to_id)
+ url = url_for_commit_range(project, range)
- title = "Commits #{from_id} through #{to_id}"
+ title = range.reference_title
klass = reference_class(:commit_range)
project_ref += '@' if project_ref
%(<a href="#{url}"
title="#{title}"
- class="#{klass}">#{project_ref}#{commit_range}</a>)
+ class="#{klass}">#{project_ref}#{range}</a>)
else
match
end
end
end
- def split_commit_range(range)
- from_id, to_id = range.split(/\.{2,3}/, 2)
- from_id << "^" if range !~ /\.{3}/
-
- [from_id, to_id]
- end
-
- def commit(id)
- unless @commit_map[id]
- @commit_map[id] = project.commit(id)
- end
-
- @commit_map[id]
- end
-
- def valid_range?(project, from_id, to_id)
- project && project.valid_repo? && commit(from_id) && commit(to_id)
- end
-
- def url_for_commit_range(project, from_id, to_id)
+ def url_for_commit_range(project, range)
h = Rails.application.routes.url_helpers
h.namespace_project_compare_url(project.namespace, project,
- from: from_id, to: to_id,
- only_path: context[:only_path])
+ range.to_param.merge(only_path: context[:only_path]))
end
end
end
diff --git a/lib/gitlab/markdown/commit_reference_filter.rb b/lib/gitlab/markdown/commit_reference_filter.rb
index 66598127f6e..b20b29f5d0c 100644
--- a/lib/gitlab/markdown/commit_reference_filter.rb
+++ b/lib/gitlab/markdown/commit_reference_filter.rb
@@ -48,6 +48,8 @@ module Gitlab
project = self.project_from_ref(project_ref)
if commit = commit_from_ref(project, commit_ref)
+ push_result(:commit, commit)
+
url = url_for_commit(project, commit)
title = escape_once(commit.link_title)
@@ -57,7 +59,7 @@ module Gitlab
%(<a href="#{url}"
title="#{title}"
- class="#{klass}">#{project_ref}#{commit_ref}</a>)
+ class="#{klass}">#{project_ref}#{commit.short_id}</a>)
else
match
end
diff --git a/lib/gitlab/markdown/issue_reference_filter.rb b/lib/gitlab/markdown/issue_reference_filter.rb
index c9267cc3e9d..4b360369d37 100644
--- a/lib/gitlab/markdown/issue_reference_filter.rb
+++ b/lib/gitlab/markdown/issue_reference_filter.rb
@@ -48,6 +48,9 @@ module Gitlab
project = self.project_from_ref(project_ref)
if project && project.issue_exists?(issue)
+ # FIXME (rspeicher): Law of Demeter
+ push_result(:issue, project.issues.where(iid: issue).first)
+
url = url_for_issue(issue, project, only_path: context[:only_path])
title = escape_once("Issue: #{title_for_issue(issue, project)}")
diff --git a/lib/gitlab/markdown/label_reference_filter.rb b/lib/gitlab/markdown/label_reference_filter.rb
index 4c21192c0d3..a357f28458d 100644
--- a/lib/gitlab/markdown/label_reference_filter.rb
+++ b/lib/gitlab/markdown/label_reference_filter.rb
@@ -52,11 +52,13 @@ module Gitlab
params = label_params(id, name)
if label = project.labels.find_by(params)
- url = url_for_label(project, label)
+ push_result(:label, label)
+ url = url_for_label(project, label)
klass = reference_class(:label)
- %(<a href="#{url}" class="#{klass}">#{render_colored_label(label)}</a>)
+ %(<a href="#{url}"
+ class="#{klass}">#{render_colored_label(label)}</a>)
else
match
end
diff --git a/lib/gitlab/markdown/merge_request_reference_filter.rb b/lib/gitlab/markdown/merge_request_reference_filter.rb
index 40239523cda..7c28fe112ef 100644
--- a/lib/gitlab/markdown/merge_request_reference_filter.rb
+++ b/lib/gitlab/markdown/merge_request_reference_filter.rb
@@ -48,6 +48,8 @@ module Gitlab
project = self.project_from_ref(project_ref)
if project && merge_request = project.merge_requests.find_by(iid: id)
+ push_result(:merge_request, merge_request)
+
title = escape_once("Merge Request: #{merge_request.title}")
klass = reference_class(:merge_request)
diff --git a/lib/gitlab/markdown/reference_filter.rb b/lib/gitlab/markdown/reference_filter.rb
index ef4aa408a7e..a4303d96bef 100644
--- a/lib/gitlab/markdown/reference_filter.rb
+++ b/lib/gitlab/markdown/reference_filter.rb
@@ -12,7 +12,15 @@ module Gitlab
# :reference_class - Custom CSS class added to reference links.
# :only_path - Generate path-only links.
#
+ # Results:
+ # :references - A Hash of references that were found and replaced.
class ReferenceFilter < HTML::Pipeline::Filter
+ def initialize(*args)
+ super
+
+ result[:references] = Hash.new { |hash, type| hash[type] = [] }
+ end
+
def escape_once(html)
ERB::Util.html_escape_once(html)
end
@@ -29,6 +37,16 @@ module Gitlab
context[:project]
end
+ # Add a reference to the pipeline's result Hash
+ #
+ # type - Singular Symbol reference type (e.g., :issue, :user, etc.)
+ # values - One or more Objects to add
+ def push_result(type, *values)
+ return if values.empty?
+
+ result[:references][type].push(*values)
+ end
+
def reference_class(type)
"gfm gfm-#{type} #{context[:reference_class]}".strip
end
diff --git a/lib/gitlab/markdown/snippet_reference_filter.rb b/lib/gitlab/markdown/snippet_reference_filter.rb
index ada67de992b..64a0a2696f7 100644
--- a/lib/gitlab/markdown/snippet_reference_filter.rb
+++ b/lib/gitlab/markdown/snippet_reference_filter.rb
@@ -48,6 +48,8 @@ module Gitlab
project = self.project_from_ref(project_ref)
if project && snippet = project.snippets.find_by(id: id)
+ push_result(:snippet, snippet)
+
title = escape_once("Snippet: #{snippet.title}")
klass = reference_class(:snippet)
diff --git a/lib/gitlab/markdown/user_reference_filter.rb b/lib/gitlab/markdown/user_reference_filter.rb
index 5fc8ed55fe2..28ec041b1d4 100644
--- a/lib/gitlab/markdown/user_reference_filter.rb
+++ b/lib/gitlab/markdown/user_reference_filter.rb
@@ -38,27 +38,11 @@ module Gitlab
# Returns a String with `@user` references replaced with links. All links
# have `gfm` and `gfm-project_member` class names attached for styling.
def user_link_filter(text)
- project = context[:project]
-
- self.class.references_in(text) do |match, user|
- klass = reference_class(:project_member)
-
- if user == 'all'
- url = link_to_all(project)
-
- %(<a href="#{url}" class="#{klass}">@#{user}</a>)
- elsif namespace = Namespace.find_by(path: user)
- if namespace.is_a?(Group)
- if user_can_reference_group?(namespace)
- url = group_url(user, only_path: context[:only_path])
- %(<a href="#{url}" class="#{klass}">@#{user}</a>)
- else
- match
- end
- else
- url = user_url(user, only_path: context[:only_path])
- %(<a href="#{url}" class="#{klass}">@#{user}</a>)
- end
+ self.class.references_in(text) do |match, username|
+ if username == 'all'
+ link_to_all
+ elsif namespace = Namespace.find_by(path: username)
+ link_to_namespace(namespace) || match
else
match
end
@@ -71,17 +55,46 @@ module Gitlab
Rails.application.routes.url_helpers
end
- def group_url(*args)
- urls.group_url(*args)
+ def link_class
+ reference_class(:project_member)
+ end
+
+ def link_to_all
+ project = context[:project]
+
+ # FIXME (rspeicher): Law of Demeter
+ push_result(:user, *project.team.members.flatten)
+
+ url = urls.namespace_project_url(project.namespace, project,
+ only_path: context[:only_path])
+
+ %(<a href="#{url}" class="#{link_class}">@all</a>)
+ end
+
+ def link_to_namespace(namespace)
+ if namespace.is_a?(Group)
+ link_to_group(namespace.path, namespace)
+ else
+ link_to_user(namespace.path, namespace)
+ end
end
- def user_url(*args)
- urls.user_url(*args)
+ def link_to_group(group, namespace)
+ return unless user_can_reference_group?(namespace)
+
+ push_result(:user, *namespace.users)
+
+ url = urls.group_url(group, only_path: context[:only_path])
+
+ %(<a href="#{url}" class="#{link_class}">@#{group}</a>)
end
- def link_to_all(project)
- urls.namespace_project_url(project.namespace, project,
- only_path: context[:only_path])
+ def link_to_user(user, namespace)
+ push_result(:user, namespace.owner)
+
+ url = urls.user_url(user, only_path: context[:only_path])
+
+ %(<a href="#{url}" class="#{link_class}">@#{user}</a>)
end
def user_can_reference_group?(group)
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 949dd5d26b1..e35f848fa6e 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -8,151 +8,70 @@ module Gitlab
@current_user = current_user
end
- def can?(user, action, subject)
- Ability.abilities.allowed?(user, action, subject)
- end
-
def analyze(text)
- text = text.dup
-
- # Remove preformatted/code blocks so that references are not included
- text.gsub!(/^```.*?^```/m, '')
- text.gsub!(/[^`]`[^`]*?`[^`]/, '')
-
- @references = Hash.new { |hash, type| hash[type] = [] }
- parse_references(text)
+ @_text = text.dup
end
- # Given a valid project, resolve the extracted identifiers of the requested type to
- # model objects.
-
def users
- references[:user].uniq.map do |project, identifier|
- if identifier == "all"
- project.team.members.flatten
- elsif namespace = Namespace.find_by(path: identifier)
- if namespace.is_a?(Group)
- namespace.users if can?(current_user, :read_group, namespace)
- else
- namespace.owner
- end
- end
- end.flatten.compact.uniq
+ result = pipeline_result(:user)
+ result.uniq
end
def labels
- references[:label].uniq.map do |project, identifier|
- project.labels.where(id: identifier).first
- end.compact.uniq
+ result = pipeline_result(:label)
+ result.uniq
end
def issues
- references[:issue].uniq.map do |project, identifier|
- if project.default_issues_tracker?
- project.issues.where(iid: identifier).first
- end
- end.compact.uniq
+ # TODO (rspeicher): What about external issues?
+
+ result = pipeline_result(:issue)
+ result.uniq
end
def merge_requests
- references[:merge_request].uniq.map do |project, identifier|
- project.merge_requests.where(iid: identifier).first
- end.compact.uniq
+ result = pipeline_result(:merge_request)
+ result.uniq
end
def snippets
- references[:snippet].uniq.map do |project, identifier|
- project.snippets.where(id: identifier).first
- end.compact.uniq
+ result = pipeline_result(:snippet)
+ result.uniq
end
def commits
- references[:commit].uniq.map do |project, identifier|
- repo = project.repository
- repo.commit(identifier) if repo
- end.compact.uniq
+ result = pipeline_result(:commit)
+ result.uniq
end
def commit_ranges
- references[:commit_range].uniq.map do |project, identifier|
- repo = project.repository
- if repo
- from_id, to_id = identifier.split(/\.{2,3}/, 2)
- [repo.commit(from_id), repo.commit(to_id)]
- end
- end.compact.uniq
+ result = pipeline_result(:commit_range)
+ result.uniq
end
private
- NAME_STR = Gitlab::Regex::NAMESPACE_REGEX_STR
- PROJ_STR = "(?<project>#{NAME_STR}/#{NAME_STR})"
-
- REFERENCE_PATTERN = %r{
- (?<prefix>\W)? # Prefix
- ( # Reference
- @(?<user>#{NAME_STR}) # User name
- |~(?<label>\d+) # Label ID
- |(?<issue>([A-Z\-]+-)\d+) # JIRA Issue ID
- |#{PROJ_STR}?\#(?<issue>([a-zA-Z\-]+-)?\d+) # Issue ID
- |#{PROJ_STR}?!(?<merge_request>\d+) # MR ID
- |\$(?<snippet>\d+) # Snippet ID
- |(#{PROJ_STR}@)?(?<commit_range>[\h]{6,40}\.{2,3}[\h]{6,40}) # Commit range
- |(#{PROJ_STR}@)?(?<commit>[\h]{6,40}) # Commit ID
- )
- (?<suffix>\W)? # Suffix
- }x.freeze
-
- TYPES = %i(user issue label merge_request snippet commit commit_range).freeze
-
- def parse_references(text, project = @project)
- # parse reference links
- text.gsub!(REFERENCE_PATTERN) do |match|
- type = TYPES.detect { |t| $~[t].present? }
-
- actual_project = project
- project_prefix = nil
- project_path = $LAST_MATCH_INFO[:project]
- if project_path
- actual_project = ::Project.find_with_namespace(project_path)
- actual_project = nil unless can?(current_user, :read_project, actual_project)
- project_prefix = project_path
- end
-
- parse_result($LAST_MATCH_INFO, type,
- actual_project, project_prefix) || match
- end
- end
-
- # Called from #parse_references. Attempts to build a gitlab reference
- # link. Returns nil if +type+ is nil, if the match string is an HTML
- # entity, if the reference is invalid, or if the matched text includes an
- # invalid project path.
- def parse_result(match_info, type, project, project_prefix)
- prefix = match_info[:prefix]
- suffix = match_info[:suffix]
-
- return nil if html_entity?(prefix, suffix) || type.nil?
- return nil if project.nil? && !project_prefix.nil?
-
- identifier = match_info[type]
- ref_link = reference_link(type, identifier, project, project_prefix)
-
- if ref_link
- "#{prefix}#{ref_link}#{suffix}"
- else
- nil
- end
- end
-
- # Return true if the +prefix+ and +suffix+ indicate that the matched string
- # is an HTML entity like &amp;
- def html_entity?(prefix, suffix)
- prefix && suffix && prefix[0] == '&' && suffix[-1] == ';'
- end
-
- def reference_link(type, identifier, project, _)
- references[type] << [project, identifier]
+ # Instantiate and call HTML::Pipeline with a single reference filter type,
+ # returning the result
+ #
+ # filter_type - Symbol reference type (e.g., :commit, :issue, etc.)
+ #
+ # Returns the results Array for the requested filter type
+ def pipeline_result(filter_type)
+ klass = filter_type.to_s.camelize + 'ReferenceFilter'
+ filter = "Gitlab::Markdown::#{klass}".constantize
+
+ context = {
+ project: project,
+ current_user: current_user,
+ # We don't actually care about the links generated
+ only_path: true
+ }
+
+ pipeline = HTML::Pipeline.new([filter], context)
+ result = pipeline.call(@_text)
+
+ result[:references][filter_type]
end
end
end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index 0571574aa4f..9f1adc860d1 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -15,20 +15,20 @@ module Gitlab
def namespace_name_regex
- @namespace_name_regex ||= /\A[a-zA-Z0-9_\-\. ]*\z/.freeze
+ @namespace_name_regex ||= /\A[\p{Alnum}\p{Pd}_\. ]*\z/.freeze
end
def namespace_name_regex_message
- "can contain only letters, digits, '_', '-', '.' and space."
+ "can contain only letters, digits, '_', '.', dash and space."
end
def project_name_regex
- @project_name_regex ||= /\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\. ]*\z/.freeze
+ @project_name_regex ||= /\A[\p{Alnum}_][\p{Alnum}\p{Pd}_\. ]*\z/.freeze
end
def project_name_regex_message
- "can contain only letters, digits, '_', '-', '.' and space. " \
+ "can contain only letters, digits, '_', '.', dash and space. " \
"It must start with letter, digit or '_'."
end
diff --git a/lib/gitlab/theme.rb b/lib/gitlab/theme.rb
index 43093c7d27e..f0e61aa2e81 100644
--- a/lib/gitlab/theme.rb
+++ b/lib/gitlab/theme.rb
@@ -7,33 +7,44 @@ module Gitlab
COLOR = 5 unless const_defined?(:COLOR)
BLUE = 6 unless const_defined?(:BLUE)
- def self.css_class_by_id(id)
- themes = {
- BASIC => "ui_basic",
- MARS => "ui_mars",
- MODERN => "ui_modern",
- GRAY => "ui_gray",
- COLOR => "ui_color",
- BLUE => "ui_blue"
+ def self.classes
+ @classes ||= {
+ BASIC => 'ui_basic',
+ MARS => 'ui_mars',
+ MODERN => 'ui_modern',
+ GRAY => 'ui_gray',
+ COLOR => 'ui_color',
+ BLUE => 'ui_blue'
}
+ end
+ def self.css_class_by_id(id)
id ||= Gitlab.config.gitlab.default_theme
-
- themes[id]
+ classes[id]
end
- def self.type_css_class_by_id(id)
- types = {
+ def self.types
+ @types ||= {
BASIC => 'light_theme',
MARS => 'dark_theme',
MODERN => 'dark_theme',
GRAY => 'dark_theme',
- COLOR => 'dark_theme'
+ COLOR => 'dark_theme',
+ BLUE => 'light_theme'
}
+ end
+ def self.type_css_class_by_id(id)
id ||= Gitlab.config.gitlab.default_theme
-
types[id]
end
+
+ # Convenience method to get a space-separated String of all the theme
+ # classes that mighty be applied to the `body` element
+ #
+ # Returns a String
+ def self.body_classes
+ (classes.values + types.values).uniq.join(' ')
+ end
end
end
diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake
index 058c7417040..b22c631c8ba 100644
--- a/lib/tasks/dev.rake
+++ b/lib/tasks/dev.rake
@@ -7,4 +7,9 @@ namespace :dev do
Rake::Task["gitlab:setup"].invoke
Rake::Task["gitlab:shell:setup"].invoke
end
+
+ desc 'GITLAB | Start/restart foreman and watch for changes'
+ task :foreman => :environment do
+ sh 'rerun --dir app,config,lib -- foreman start'
+ end
end
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index 04a2eb12db0..1a6303b6c82 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -282,7 +282,8 @@ namespace :gitlab do
def check_redis_version
print "Redis version >= 2.0.0? ... "
- if run_and_match(%W(redis-cli --version), /redis-cli 2.\d.\d/)
+ redis_version = run(%W(redis-cli --version))
+ if redis_version.try(:match, /redis-cli 2.\d.\d/) || redis_version.try(:match, /redis-cli 3.\d.\d/)
puts "yes".green
else
puts "no".red
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index e99c3f5bc11..e98b75afabc 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -117,34 +117,41 @@ describe SubmoduleHelper do
context 'submodules with relative links' do
let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
+ let(:commit_id) { sample_commit[:id] }
before do
self.instance_variable_set(:@project, project)
end
it 'one level down' do
- commit_id = sample_commit[:id]
result = relative_self_links('../test.git', commit_id)
expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"])
end
it 'two levels down' do
- commit_id = sample_commit[:id]
result = relative_self_links('../../test.git', commit_id)
expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"])
end
it 'one level down with namespace and repo' do
- commit_id = sample_commit[:id]
result = relative_self_links('../foobar/test.git', commit_id)
expect(result).to eq(["/foobar/test", "/foobar/test/tree/#{commit_id}"])
end
it 'two levels down with namespace and repo' do
- commit_id = sample_commit[:id]
result = relative_self_links('../foobar/baz/test.git', commit_id)
expect(result).to eq(["/baz/test", "/baz/test/tree/#{commit_id}"])
end
+
+ context 'personal project' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, namespace: user.namespace) }
+
+ it 'one level down with personal project' do
+ result = relative_self_links('../test.git', commit_id)
+ expect(result).to eq(["/#{user.username}/test", "/#{user.username}/test/tree/#{commit_id}"])
+ end
+ end
end
end
diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb
new file mode 100644
index 00000000000..3840e64981f
--- /dev/null
+++ b/spec/helpers/visibility_level_helper_spec.rb
@@ -0,0 +1,75 @@
+require 'spec_helper'
+
+describe VisibilityLevelHelper do
+ include Haml::Helpers
+
+ before :all do
+ init_haml_helpers
+ end
+
+ let(:project) { create(:project) }
+
+ describe 'visibility_level_description' do
+ shared_examples 'a visibility level description' do
+ let(:desc) do
+ visibility_level_description(Gitlab::VisibilityLevel::PRIVATE,
+ form_model)
+ end
+
+ let(:expected_class) do
+ class_name = case form_model.class.name
+ when 'String'
+ form_model
+ else
+ form_model.class.name
+ end
+
+ class_name.match(/(project|snippet)$/i)[0]
+ end
+
+ it 'should refer to the correct class' do
+ expect(desc).to match(/#{expected_class}/i)
+ end
+ end
+
+ context 'form_model argument is a String' do
+ context 'model object is a personal snippet' do
+ it_behaves_like 'a visibility level description' do
+ let(:form_model) { 'PersonalSnippet' }
+ end
+ end
+
+ context 'model object is a project snippet' do
+ it_behaves_like 'a visibility level description' do
+ let(:form_model) { 'ProjectSnippet' }
+ end
+ end
+
+ context 'model object is a project' do
+ it_behaves_like 'a visibility level description' do
+ let(:form_model) { 'Project' }
+ end
+ end
+ end
+
+ context 'form_model argument is a model object' do
+ context 'model object is a personal snippet' do
+ it_behaves_like 'a visibility level description' do
+ let(:form_model) { create(:personal_snippet) }
+ end
+ end
+
+ context 'model object is a project snippet' do
+ it_behaves_like 'a visibility level description' do
+ let(:form_model) { create(:project_snippet, project: project) }
+ end
+ end
+
+ context 'model object is a project' do
+ it_behaves_like 'a visibility level description' do
+ let(:form_model) { project }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
index f0804ce0056..7274cb309a0 100644
--- a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
@@ -42,13 +42,17 @@ module Gitlab::Markdown
reference = "#{commit1.short_id}...#{commit2.id}"
reference2 = "#{commit1.id}...#{commit2.short_id}"
- expect(filter("See #{reference}").css('a').first.text).to eq reference
- expect(filter("See #{reference2}").css('a').first.text).to eq reference2
+ exp = commit1.short_id + '...' + commit2.short_id
+
+ expect(filter("See #{reference}").css('a').first.text).to eq exp
+ expect(filter("See #{reference2}").css('a').first.text).to eq exp
end
it 'links with adjacent text' do
doc = filter("See (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+
+ exp = Regexp.escape("#{commit1.short_id}...#{commit2.short_id}")
+ expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
end
it 'ignores invalid commit IDs' do
@@ -81,6 +85,11 @@ module Gitlab::Markdown
expect(link).not_to match %r(https?://)
expect(link).to eq urls.namespace_project_compare_url(project.namespace, project, from: commit1.id, to: commit2.id, only_path: true)
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("See #{reference}")
+ expect(result[:references][:commit_range]).not_to be_empty
+ end
end
context 'cross-project reference' do
@@ -102,7 +111,9 @@ module Gitlab::Markdown
it 'links with adjacent text' do
doc = filter("Fixed (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+
+ exp = Regexp.escape("#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}")
+ expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
end
it 'ignores invalid commit IDs on the referenced project' do
@@ -112,6 +123,11 @@ module Gitlab::Markdown
exp = act = "Fixed #{project2.path_with_namespace}##{commit1.id}...#{commit2.id.reverse}"
expect(filter(act).to_html).to eq exp
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("See #{reference}")
+ expect(result[:references][:commit_range]).not_to be_empty
+ end
end
context 'when user cannot access reference' do
diff --git a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
index f792d7f696e..cc32a4fcf03 100644
--- a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
@@ -27,15 +27,23 @@ module Gitlab::Markdown
it "links to a valid reference of #{size} characters" do
doc = filter("See #{reference[0...size]}")
- expect(doc.css('a').first.text).to eq reference[0...size]
+ expect(doc.css('a').first.text).to eq commit.short_id
expect(doc.css('a').first.attr('href')).
to eq urls.namespace_project_commit_url(project.namespace, project, reference)
end
end
+ it 'always uses the short ID as the link text' do
+ doc = filter("See #{commit.id}")
+ expect(doc.text).to eq "See #{commit.short_id}"
+
+ doc = filter("See #{commit.id[0...6]}")
+ expect(doc.text).to eq "See #{commit.short_id}"
+ end
+
it 'links with adjacent text' do
doc = filter("See (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+ expect(doc.to_html).to match(/\(<a.+>#{commit.short_id}<\/a>\.\)/)
end
it 'ignores invalid commit IDs' do
@@ -55,7 +63,7 @@ module Gitlab::Markdown
allow_any_instance_of(Commit).to receive(:title).and_return(%{"></a>whatever<a title="})
doc = filter("See #{reference}")
- expect(doc.text).to eq "See #{commit.id}"
+ expect(doc.text).to eq "See #{commit.short_id}"
end
it 'includes default classes' do
@@ -75,6 +83,11 @@ module Gitlab::Markdown
expect(link).not_to match %r(https?://)
expect(link).to eq urls.namespace_project_commit_url(project.namespace, project, reference, only_path: true)
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("See #{reference}")
+ expect(result[:references][:commit]).not_to be_empty
+ end
end
context 'cross-project reference' do
@@ -95,13 +108,20 @@ module Gitlab::Markdown
it 'links with adjacent text' do
doc = filter("Fixed (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+
+ exp = Regexp.escape(project2.path_with_namespace)
+ expect(doc.to_html).to match(/\(<a.+>#{exp}@#{commit.short_id}<\/a>\.\)/)
end
it 'ignores invalid commit IDs on the referenced project' do
exp = act = "Committed #{project2.path_with_namespace}##{commit.id.reverse}"
expect(filter(act).to_html).to eq exp
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("See #{reference}")
+ expect(result[:references][:commit]).not_to be_empty
+ end
end
context 'when user cannot access reference' do
diff --git a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
index f95b37d6954..393bf32e196 100644
--- a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
@@ -34,7 +34,7 @@ module Gitlab::Markdown
end
it 'links to a valid reference' do
- doc = filter("See #{reference}")
+ doc = filter("Fixed #{reference}")
expect(doc.css('a').first.attr('href')).
to eq helper.url_for_issue(issue.iid, project)
@@ -81,6 +81,11 @@ module Gitlab::Markdown
expect(link).not_to match %r(https?://)
expect(link).to eq helper.url_for_issue(issue.iid, project, only_path: true)
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("Fixed #{reference}")
+ expect(result[:references][:issue]).to eq [issue]
+ end
end
context 'cross-project reference' do
@@ -117,6 +122,11 @@ module Gitlab::Markdown
expect(filter(act).to_html).to eq exp
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("Fixed #{reference}")
+ expect(result[:references][:issue]).to eq [issue]
+ end
end
context 'when user cannot access reference' do
diff --git a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
index c84e568e172..9f898837466 100644
--- a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
@@ -39,6 +39,11 @@ module Gitlab::Markdown
expect(link).to eq urls.namespace_project_issues_url(project.namespace, project, label_name: label.name, only_path: true)
end
+ it 'adds to the results hash' do
+ result = pipeline_result("Label #{reference}")
+ expect(result[:references][:label]).to eq [label]
+ end
+
describe 'label span element' do
it 'includes default classes' do
doc = filter("Label #{reference}")
diff --git a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
index 0f66442269b..d6e745114f2 100644
--- a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
@@ -69,6 +69,11 @@ module Gitlab::Markdown
expect(link).not_to match %r(https?://)
expect(link).to eq urls.namespace_project_merge_request_url(project.namespace, project, merge, only_path: true)
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("Merge #{reference}")
+ expect(result[:references][:merge_request]).to eq [merge]
+ end
end
context 'cross-project reference' do
@@ -98,6 +103,11 @@ module Gitlab::Markdown
expect(filter(act).to_html).to eq exp
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("Merge #{reference}")
+ expect(result[:references][:merge_request]).to eq [merge]
+ end
end
context 'when user cannot access reference' do
diff --git a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
index 79533a90b55..a4b331157af 100644
--- a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
@@ -68,6 +68,11 @@ module Gitlab::Markdown
expect(link).not_to match %r(https?://)
expect(link).to eq urls.namespace_project_snippet_url(project.namespace, project, snippet, only_path: true)
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("Snippet #{reference}")
+ expect(result[:references][:snippet]).to eq [snippet]
+ end
end
context 'cross-project reference' do
@@ -96,6 +101,11 @@ module Gitlab::Markdown
expect(filter(act).to_html).to eq exp
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("Snippet #{reference}")
+ expect(result[:references][:snippet]).to eq [snippet]
+ end
end
context 'when user cannot access reference' do
diff --git a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
index a5eb927072e..922502ada33 100644
--- a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
@@ -24,9 +24,29 @@ module Gitlab::Markdown
end
end
+ context 'mentioning @all' do
+ before do
+ project.team << [project.creator, :developer]
+ end
+
+ it 'supports a special @all mention' do
+ doc = filter("Hey @all")
+ expect(doc.css('a').length).to eq 1
+ expect(doc.css('a').first.attr('href'))
+ .to eq urls.namespace_project_url(project.namespace, project)
+ end
+
+ it 'adds to the results hash' do
+ result = pipeline_result('Hey @all')
+ expect(result[:references][:user]).to eq [project.creator]
+ end
+ end
+
context 'mentioning a user' do
+ let(:reference) { "@#{user.username}" }
+
it 'links to a User' do
- doc = filter("Hey @#{user.username}")
+ doc = filter("Hey #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls.user_url(user)
end
@@ -45,22 +65,45 @@ module Gitlab::Markdown
doc = filter("Hey @#{user.username}")
expect(doc.css('a').length).to eq 1
end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("Hey #{reference}")
+ expect(result[:references][:user]).to eq [user]
+ end
end
context 'mentioning a group' do
let(:group) { create(:group) }
let(:user) { create(:user) }
- it 'links to a Group that the current user can read' do
- group.add_user(user, Gitlab::Access::DEVELOPER)
+ let(:reference) { "@#{group.name}" }
+
+ context 'that the current user can read' do
+ before do
+ group.add_user(user, Gitlab::Access::DEVELOPER)
+ end
- doc = filter("Hey @#{group.name}", current_user: user)
- expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
+ it 'links to the Group' do
+ doc = filter("Hey #{reference}", current_user: user)
+ expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
+ end
+
+ it 'adds to the results hash' do
+ result = pipeline_result("Hey #{reference}", current_user: user)
+ expect(result[:references][:user]).to eq group.users
+ end
end
- it 'ignores references to a Group that the current user cannot read' do
- doc = filter("Hey @#{group.name}", current_user: user)
- expect(doc.to_html).to eq "Hey @#{group.name}"
+ context 'that the current user cannot read' do
+ it 'ignores references to the Group' do
+ doc = filter("Hey #{reference}", current_user: user)
+ expect(doc.to_html).to eq "Hey #{reference}"
+ end
+
+ it 'does not add to the results hash' do
+ result = pipeline_result("Hey #{reference}", current_user: user)
+ expect(result[:references][:user]).to eq []
+ end
end
end
@@ -70,13 +113,6 @@ module Gitlab::Markdown
expect(doc.to_html).to match(/\(<a.+>@#{user.username}<\/a>\.\)/)
end
- it 'supports a special @all mention' do
- doc = filter("Hey @all")
- expect(doc.css('a').length).to eq 1
- expect(doc.css('a').first.attr('href'))
- .to eq urls.namespace_project_url(project.namespace, project)
- end
-
it 'includes default classes' do
doc = filter("Hey @#{user.username}")
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-project_member'
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 0f4ea2a24ed..9801dc16554 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -4,80 +4,6 @@ describe Gitlab::ReferenceExtractor do
let(:project) { create(:project) }
subject { Gitlab::ReferenceExtractor.new(project, project.creator) }
- it 'extracts username references' do
- subject.analyze('this contains a @user reference')
- expect(subject.references[:user]).to eq([[project, 'user']])
- end
-
- it 'extracts issue references' do
- subject.analyze('this one talks about issue #1234')
- expect(subject.references[:issue]).to eq([[project, '1234']])
- end
-
- it 'extracts JIRA issue references' do
- subject.analyze('this one talks about issue JIRA-1234')
- expect(subject.references[:issue]).to eq([[project, 'JIRA-1234']])
- end
-
- it 'extracts merge request references' do
- subject.analyze("and here's !43, a merge request")
- expect(subject.references[:merge_request]).to eq([[project, '43']])
- end
-
- it 'extracts snippet ids' do
- subject.analyze('snippets like $12 get extracted as well')
- expect(subject.references[:snippet]).to eq([[project, '12']])
- end
-
- it 'extracts commit shas' do
- subject.analyze('commit shas 98cf0ae3 are pulled out as Strings')
- expect(subject.references[:commit]).to eq([[project, '98cf0ae3']])
- end
-
- it 'extracts commit ranges' do
- subject.analyze('here you go, a commit range: 98cf0ae3...98cf0ae4')
- expect(subject.references[:commit_range]).to eq([[project, '98cf0ae3...98cf0ae4']])
- end
-
- it 'extracts multiple references and preserves their order' do
- subject.analyze('@me and @you both care about this')
- expect(subject.references[:user]).to eq([
- [project, 'me'],
- [project, 'you']
- ])
- end
-
- it 'leaves the original note unmodified' do
- text = 'issue #123 is just the worst, @user'
- subject.analyze(text)
- expect(text).to eq('issue #123 is just the worst, @user')
- end
-
- it 'extracts no references for <pre>..</pre> blocks' do
- subject.analyze("<pre>def puts '#1 issue'\nend\n</pre>```")
- expect(subject.issues).to be_blank
- end
-
- it 'extracts no references for <code>..</code> blocks' do
- subject.analyze("<code>def puts '!1 request'\nend\n</code>```")
- expect(subject.merge_requests).to be_blank
- end
-
- it 'extracts no references for code blocks with language' do
- subject.analyze("this code:\n```ruby\ndef puts '#1 issue'\nend\n```")
- expect(subject.issues).to be_blank
- end
-
- it 'extracts issue references for invalid code blocks' do
- subject.analyze('test: ```this one talks about issue #1234```')
- expect(subject.references[:issue]).to eq([[project, '1234']])
- end
-
- it 'handles all possible kinds of references' do
- accessors = described_class::TYPES.map { |t| "#{t}s".to_sym }
- expect(subject).to respond_to(*accessors)
- end
-
it 'accesses valid user objects' do
@u_foo = create(:user, username: 'foo')
@u_bar = create(:user, username: 'bar')
@@ -139,12 +65,12 @@ describe Gitlab::ReferenceExtractor do
earlier_commit = project.commit('master~2')
subject.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}")
+
extracted = subject.commit_ranges
expect(extracted.size).to eq(1)
- expect(extracted[0][0].sha).to eq(earlier_commit.sha)
- expect(extracted[0][0].message).to eq(earlier_commit.message)
- expect(extracted[0][1].sha).to eq(commit.sha)
- expect(extracted[0][1].message).to eq(commit.message)
+ expect(extracted.first).to be_kind_of(CommitRange)
+ expect(extracted.first.commit_from).to eq earlier_commit
+ expect(extracted.first.commit_to).to eq commit
end
context 'with a project with an underscore' do
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 727884c41c5..7fdc8fa600d 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -1,3 +1,4 @@
+# coding: utf-8
require 'spec_helper'
describe Gitlab::Regex do
@@ -16,6 +17,8 @@ describe Gitlab::Regex do
it { expect('GitLab CE').to match(Gitlab::Regex.project_name_regex) }
it { expect('100 lines').to match(Gitlab::Regex.project_name_regex) }
it { expect('gitlab.git').to match(Gitlab::Regex.project_name_regex) }
+ it { expect('Český název').to match(Gitlab::Regex.project_name_regex) }
+ it { expect('Dash – is this').to match(Gitlab::Regex.project_name_regex) }
it { expect('?gitlab').not_to match(Gitlab::Regex.project_name_regex) }
end
end
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
new file mode 100644
index 00000000000..31ee3e99cad
--- /dev/null
+++ b/spec/models/commit_range_spec.rb
@@ -0,0 +1,120 @@
+require 'spec_helper'
+
+describe CommitRange do
+ let(:sha_from) { 'f3f85602' }
+ let(:sha_to) { 'e86e1013' }
+
+ let(:range) { described_class.new("#{sha_from}...#{sha_to}") }
+ let(:range2) { described_class.new("#{sha_from}..#{sha_to}") }
+
+ it 'raises ArgumentError when given an invalid range string' do
+ expect { described_class.new("Foo") }.to raise_error
+ end
+
+ describe '#to_s' do
+ it 'is correct for three-dot syntax' do
+ expect(range.to_s).to eq "#{sha_from[0..7]}...#{sha_to[0..7]}"
+ end
+
+ it 'is correct for two-dot syntax' do
+ expect(range2.to_s).to eq "#{sha_from[0..7]}..#{sha_to[0..7]}"
+ end
+ end
+
+ describe '#reference_title' do
+ it 'returns the correct String for three-dot ranges' do
+ expect(range.reference_title).to eq "Commits #{sha_from} through #{sha_to}"
+ end
+
+ it 'returns the correct String for two-dot ranges' do
+ expect(range2.reference_title).to eq "Commits #{sha_from}^ through #{sha_to}"
+ end
+ end
+
+ describe '#to_param' do
+ it 'includes the correct keys' do
+ expect(range.to_param.keys).to eq %i(from to)
+ end
+
+ it 'includes the correct values for a three-dot range' do
+ expect(range.to_param).to eq({from: sha_from, to: sha_to})
+ end
+
+ it 'includes the correct values for a two-dot range' do
+ expect(range2.to_param).to eq({from: sha_from + '^', to: sha_to})
+ end
+ end
+
+ describe '#exclude_start?' do
+ it 'is false for three-dot ranges' do
+ expect(range.exclude_start?).to eq false
+ end
+
+ it 'is true for two-dot ranges' do
+ expect(range2.exclude_start?).to eq true
+ end
+ end
+
+ describe '#valid_commits?' do
+ context 'without a project' do
+ it 'returns nil' do
+ expect(range.valid_commits?).to be_nil
+ end
+ end
+
+ it 'accepts an optional project argument' do
+ project1 = double('project1').as_null_object
+ project2 = double('project2').as_null_object
+
+ # project1 gets assigned through the accessor, but ignored when not given
+ # as an argument to `valid_commits?`
+ expect(project1).not_to receive(:present?)
+ range.project = project1
+
+ # project2 gets passed to `valid_commits?`
+ expect(project2).to receive(:present?).and_return(false)
+
+ range.valid_commits?(project2)
+ end
+
+ context 'with a project' do
+ let(:project) { double('project', repository: double('repository')) }
+
+ context 'with a valid repo' do
+ before do
+ expect(project).to receive(:valid_repo?).and_return(true)
+ range.project = project
+ end
+
+ it 'is false when `sha_from` is invalid' do
+ expect(project.repository).to receive(:commit).with(sha_from).and_return(false)
+ expect(project.repository).not_to receive(:commit).with(sha_to)
+ expect(range).not_to be_valid_commits
+ end
+
+ it 'is false when `sha_to` is invalid' do
+ expect(project.repository).to receive(:commit).with(sha_from).and_return(true)
+ expect(project.repository).to receive(:commit).with(sha_to).and_return(false)
+ expect(range).not_to be_valid_commits
+ end
+
+ it 'is true when both `sha_from` and `sha_to` are valid' do
+ expect(project.repository).to receive(:commit).with(sha_from).and_return(true)
+ expect(project.repository).to receive(:commit).with(sha_to).and_return(true)
+ expect(range).to be_valid_commits
+ end
+ end
+
+ context 'without a valid repo' do
+ before do
+ expect(project).to receive(:valid_repo?).and_return(false)
+ range.project = project
+ end
+
+ it 'returns false' do
+ expect(range).not_to be_valid_commits
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index 8ab847e6432..348f83c56ad 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -213,5 +213,21 @@ describe HipchatService do
"<pre>snippet note</pre>")
end
end
+
+ context "#message_options" do
+ it "should be set to the defaults" do
+ expect(hipchat.send(:message_options)).to eq({notify: false, color: 'yellow'})
+ end
+
+ it "should set notfiy to true" do
+ hipchat.stub(notify: '1')
+ expect(hipchat.send(:message_options)).to eq({notify: true, color: 'yellow'})
+ end
+
+ it "should set the color" do
+ hipchat.stub(color: 'red')
+ expect(hipchat.send(:message_options)).to eq({notify: false, color: 'red'})
+ end
+ end
end
end
diff --git a/spec/requests/api/fork_spec.rb b/spec/requests/api/fork_spec.rb
index fb3ff552c8d..7a784796031 100644
--- a/spec/requests/api/fork_spec.rb
+++ b/spec/requests/api/fork_spec.rb
@@ -50,7 +50,6 @@ describe API::API, api: true do
it 'should fail if forked project exists in the user namespace' do
post api("/projects/fork/#{project.id}", user)
expect(response.status).to eq(409)
- expect(json_response['message']['base']).to eq(['Invalid fork destination'])
expect(json_response['message']['name']).to eq(['has already been taken'])
expect(json_response['message']['path']).to eq(['has already been taken'])
end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index c9025bdf133..f158ac87e2b 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -27,7 +27,7 @@ describe Projects::ForkService do
it "fails due to transaction failure" do
@to_project = fork_project(@from_project, @to_user, false)
expect(@to_project.errors).not_to be_empty
- expect(@to_project.errors[:base]).to include("Fork transaction failed.")
+ expect(@to_project.errors[:base]).to include("Failed to fork repository")
end
end
@@ -36,8 +36,8 @@ describe Projects::ForkService do
@existing_project = create(:project, creator_id: @to_user.id, name: @from_project.name, namespace: @to_namespace)
@to_project = fork_project(@from_project, @to_user)
expect(@existing_project.persisted?).to be_truthy
- expect(@to_project.errors[:base]).to include("Invalid fork destination")
- expect(@to_project.errors[:base]).not_to include("Fork transaction failed.")
+ expect(@to_project.errors[:name]).to eq(['has already been taken'])
+ expect(@to_project.errors[:path]).to eq(['has already been taken'])
end
end
@@ -81,7 +81,7 @@ describe Projects::ForkService do
context 'fork project for group when user not owner' do
it 'group developer should fail to fork project into the group' do
to_project = fork_project(@project, @developer, true, @opts)
- expect(to_project.errors[:namespace]).to eq(['insufficient access rights'])
+ expect(to_project.errors[:namespace]).to eq(['is not valid'])
end
end
@@ -91,7 +91,6 @@ describe Projects::ForkService do
namespace: @group)
to_project = fork_project(@project, @group_owner, true, @opts)
expect(existing_project.persisted?).to be_truthy
- expect(to_project.errors[:base]).to eq(['Invalid fork destination'])
expect(to_project.errors[:name]).to eq(['has already been taken'])
expect(to_project.errors[:path]).to eq(['has already been taken'])
end
@@ -99,10 +98,7 @@ describe Projects::ForkService do
end
def fork_project(from_project, user, fork_success = true, params = {})
- context = Projects::ForkService.new(from_project, user, params)
- shell = double('gitlab_shell')
- shell.stub(fork_repository: fork_success)
- context.stub(gitlab_shell: shell)
- context.execute
+ allow_any_instance_of(Gitlab::Shell).to receive(:fork_repository).and_return(fork_success)
+ Projects::ForkService.new(from_project, user, params).execute
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 53ccaa4fd67..8fe51cf4add 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -10,19 +10,13 @@ end
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
-require 'capybara/rails'
-require 'capybara/rspec'
require 'webmock/rspec'
require 'email_spec'
require 'sidekiq/testing/inline'
-require 'capybara/poltergeist'
-
-Capybara.javascript_driver = :poltergeist
-Capybara.default_wait_time = 10
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
-Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
+Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
WebMock.disable_net_connect!(allow_localhost: true)
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
new file mode 100644
index 00000000000..fed1ab6ee33
--- /dev/null
+++ b/spec/support/capybara.rb
@@ -0,0 +1,21 @@
+require 'capybara/rails'
+require 'capybara/rspec'
+require 'capybara/poltergeist'
+
+# Give CI some extra time
+timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 90 : 10
+
+Capybara.javascript_driver = :poltergeist
+Capybara.register_driver :poltergeist do |app|
+ Capybara::Poltergeist::Driver.new(app, js_errors: true, timeout: timeout)
+end
+
+Capybara.default_wait_time = timeout
+Capybara.ignore_hidden_elements = true
+
+unless ENV['CI'] || ENV['CI_SERVER']
+ require 'capybara-screenshot/rspec'
+
+ # Keep only the screenshots generated from the last failing test suite
+ Capybara::Screenshot.prune_strategy = :keep_last_run
+end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index 9d0af29ff99..53fb6545553 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -53,7 +53,7 @@ def common_mentionable_setup
extra_commits.each { |c| commitmap[c.short_id] = c }
allow(project.repository).to receive(:commit) { |sha| commitmap[sha] }
-
+
set_mentionable_text.call(ref_string)
end
end
diff --git a/spec/support/reference_filter_spec_helper.rb b/spec/support/reference_filter_spec_helper.rb
index 0e035f0e597..06c39e1ada5 100644
--- a/spec/support/reference_filter_spec_helper.rb
+++ b/spec/support/reference_filter_spec_helper.rb
@@ -24,6 +24,20 @@ module ReferenceFilterSpecHelper
described_class.call(html, contexts)
end
+ # Run text through HTML::Pipeline with the current filter and return the
+ # result Hash
+ #
+ # body - String text to run through the pipeline
+ # contexts - Hash context for the filter. (default: {project: project})
+ #
+ # Returns the Hash of the pipeline result
+ def pipeline_result(body, contexts = {})
+ contexts.reverse_merge!(project: project)
+
+ pipeline = HTML::Pipeline.new([described_class], contexts)
+ pipeline.call(body)
+ end
+
def allow_cross_reference!
allow_any_instance_of(described_class).
to receive(:user_can_reference_project?).and_return(true)