summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG14
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile3
-rw-r--r--app/assets/javascripts/users_select.js.coffee8
-rw-r--r--app/assets/stylesheets/pages/events.scss3
-rw-r--r--app/controllers/admin/deploy_keys_controller.rb49
-rw-r--r--app/controllers/admin/users_controller.rb2
-rw-r--r--app/controllers/application_controller.rb2
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb29
-rw-r--r--app/controllers/sessions_controller.rb8
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/commits_helper.rb7
-rw-r--r--app/helpers/gitlab_markdown_helper.rb4
-rw-r--r--app/helpers/projects_helper.rb8
-rw-r--r--app/helpers/selects_helper.rb2
-rw-r--r--app/helpers/submodule_helper.rb21
-rw-r--r--app/mailers/emails/groups.rb1
-rw-r--r--app/mailers/emails/profile.rb6
-rw-r--r--app/mailers/emails/projects.rb5
-rw-r--r--app/mailers/notify.rb12
-rw-r--r--app/models/application_setting.rb2
-rw-r--r--app/models/commit.rb12
-rw-r--r--app/models/concerns/issuable.rb8
-rw-r--r--app/models/concerns/mentionable.rb37
-rw-r--r--app/models/deploy_key.rb18
-rw-r--r--app/models/deploy_keys_project.rb4
-rw-r--r--app/models/hooks/web_hook.rb2
-rw-r--r--app/models/merge_request.rb8
-rw-r--r--app/models/namespace.rb4
-rw-r--r--app/models/project.rb4
-rw-r--r--app/models/project_services/bamboo_service.rb2
-rw-r--r--app/models/project_services/buildkite_service.rb (renamed from app/models/project_services/buildbox_service.rb)4
-rw-r--r--app/models/project_services/external_wiki_service.rb2
-rw-r--r--app/models/project_services/gitlab_ci_service.rb28
-rw-r--r--app/models/project_services/irker_service.rb2
-rw-r--r--app/models/project_services/teamcity_service.rb2
-rw-r--r--app/models/repository.rb4
-rw-r--r--app/models/service.rb28
-rw-r--r--app/models/user.rb14
-rw-r--r--app/services/create_tag_service.rb4
-rw-r--r--app/services/git_push_service.rb6
-rw-r--r--app/services/notification_service.rb37
-rw-r--r--app/services/projects/fork_service.rb6
-rw-r--r--app/services/projects/participants_service.rb19
-rw-r--r--app/views/admin/deploy_keys/index.html.haml27
-rw-r--r--app/views/admin/deploy_keys/new.html.haml26
-rw-r--r--app/views/admin/deploy_keys/show.html.haml34
-rw-r--r--app/views/dashboard/projects/starred.html.haml2
-rw-r--r--app/views/layouts/nav/_admin.html.haml5
-rw-r--r--app/views/projects/deploy_keys/_deploy_key.html.haml27
-rw-r--r--app/views/projects/deploy_keys/index.html.haml25
-rw-r--r--app/views/projects/diffs/_diffs.html.haml2
-rw-r--r--app/views/projects/issues/_discussion.html.haml4
-rw-r--r--app/views/projects/issues/_issue_context.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_participants.html.haml4
-rw-r--r--app/views/shared/_issuable_filter.html.haml4
-rw-r--r--app/views/shared/_project.html.haml2
-rw-r--r--app/workers/fork_registration_worker.rb12
-rw-r--r--app/workers/post_receive.rb4
-rw-r--r--config/initializers/5_backend.rb7
-rw-r--r--config/initializers/devise.rb2
-rw-r--r--config/routes.rb4
-rw-r--r--db/migrate/20150327122227_add_public_to_key.rb5
-rw-r--r--db/migrate/20150411180045_rename_buildbox_service.rb9
-rw-r--r--db/schema.rb5
-rw-r--r--doc/api/projects.md3
-rw-r--r--doc/markdown/markdown.md4
-rw-r--r--features/admin/deploy_keys.feature21
-rw-r--r--features/project/deploy_keys.feature21
-rw-r--r--features/project/issues/issues.feature6
-rw-r--r--features/steps/admin/deploy_keys.rb57
-rw-r--r--features/steps/project/deploy_keys.rb26
-rw-r--r--features/steps/project/issues/issues.rb12
-rw-r--r--features/steps/shared/project.rb7
-rw-r--r--lib/api/entities.rb1
-rw-r--r--lib/gitlab/backend/shell.rb2
-rw-r--r--lib/gitlab/closing_issue_extractor.rb23
-rw-r--r--lib/gitlab/ldap/user.rb1
-rw-r--r--lib/gitlab/markdown.rb2
-rw-r--r--lib/gitlab/reference_extractor.rb106
-rw-r--r--spec/factories.rb3
-rw-r--r--spec/features/users_spec.rb43
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb8
-rw-r--r--spec/helpers/submodule_helper_spec.rb35
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb62
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb163
-rw-r--r--spec/models/deploy_keys_project_spec.rb27
-rw-r--r--spec/models/project_services/buildkite_service_spec.rb (renamed from spec/models/project_services/buildbox_service_spec.rb)4
-rw-r--r--spec/models/project_services/gitlab_ci_service_spec.rb21
-rw-r--r--spec/routing/project_routing_spec.rb3
-rw-r--r--spec/services/projects/fork_service_spec.rb14
-rw-r--r--spec/workers/fork_registration_worker_spec.rb10
93 files changed, 963 insertions, 381 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 0878c03207b..eab4ff4e6ad 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,9 +1,13 @@
Please view this file on the master branch, on stable branches it's out of date.
v 7.10.0 (unreleased)
+ - Fix broken file browsing with a submodule that contains a relative link (Stan Hu)
+ - Fix persistent XSS vulnerability around profile website URLs.
+ - Fix project import URL regex to prevent arbitary local repos from being imported.
- Fix bug where Wiki pages that included a '/' were no longer accessible (Stan Hu)
- Fix bug where error messages from Dropzone would not be displayed on the issues page (Stan Hu)
- Add ability to configure Reply-To address in gitlab.yml (Stan Hu)
+ - Move current user to the top of the list in assignee/author filters (Stan Hu)
- Fix broken side-by-side diff view on merge request page (Stan Hu)
- Set Application controller default URL options to ensure all url_for calls are consistent (Stan Hu)
- Allow HTML tags in Markdown input
@@ -64,10 +68,20 @@ v 7.10.0 (unreleased)
- Fixed link paths for HTTP and SSH on the admin project view (Jeremy Maziarz)
- Fix and improve help rendering (Sullivan Sénéchal)
- Fix final line in EmailsOnPush email diff being rendered as error.
+ - Authometic setup GitLab CI project for forks if origin project has GitLab CI enabled
+ - Prevent duplicate Buildkite service creation.
+ - Fix git over ssh errors 'fatal: protocol error: bad line length character'
+ - Automatically setup GitLab CI project for forks if origin project has GitLab CI enabled
+ - Bust group page project list cache when namespace name or path changes.
v 7.9.3
- Contains no changes
- Add icons to Add dropdown items.
+ - Allow admin to create public deploy keys that are accessible to any project.
+ - Warn when gitlab-shell version doesn't match requirement.
+ - Skip email confirmation when set by admin or via LDAP.
+
+ - Only allow users to reference groups, projects, issues, MRs, commits they have access to.
v 7.9.2
- Contains no changes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 42b5ce22e32..3165b7379d3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -71,7 +71,7 @@ If you can, please submit a merge request with the fix or improvements including
1. Fork the project on GitLab Cloud
1. Create a feature branch
-1. Write [tests](README.md#run-the-tests) and code
+1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG](CHANGELOG)
1. If you are changing the README, some documentation or other things which have no effect on the tests, add `[ci skip]` somewhere in the commit message
1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index e70b4523ae7..097a15a2af3 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-2.6.0
+2.6.2
diff --git a/Gemfile b/Gemfile
index a3720ce17f8..465e90e71a3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -208,7 +208,6 @@ group :development do
gem "letter_opener"
gem 'quiet_assets', '~> 1.0.1'
gem 'rack-mini-profiler', require: false
- gem "byebug"
# Better errors handler
gem 'better_errors'
@@ -257,6 +256,8 @@ group :development, :test do
gem "spring", '~> 1.3.1'
gem "spring-commands-rspec", '1.0.4'
gem "spring-commands-spinach", '1.0.0'
+
+ gem "byebug"
end
group :test do
diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee
index f464067686e..ccd85f2455d 100644
--- a/app/assets/javascripts/users_select.js.coffee
+++ b/app/assets/javascripts/users_select.js.coffee
@@ -8,6 +8,7 @@ class @UsersSelect
@groupId = $(select).data('group-id')
showNullUser = $(select).data('null-user')
showAnyUser = $(select).data('any-user')
+ firstUser = $(select).data('first-user')
$(select).select2
placeholder: "Search for a user"
@@ -32,6 +33,13 @@ class @UsersSelect
id: 0
}
+ if firstUser
+ # Move current user to the front of the list
+ for obj, index in data.results
+ if obj.username == firstUser
+ data.results.splice(index, 1)
+ data.results.unshift(obj)
+ break
if showNullUser
data.results.unshift(nullUser)
if showAnyUser
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 83daea10ed5..d4af7506d5b 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -45,7 +45,8 @@
padding: 12px 0px;
border-bottom: 1px solid #eee;
.event-title {
- @include str-truncated(72%);
+ max-width: 70%;
+ @include str-truncated(calc(100% - 174px));
font-weight: 500;
font-size: 14px;
.author_name {
diff --git a/app/controllers/admin/deploy_keys_controller.rb b/app/controllers/admin/deploy_keys_controller.rb
new file mode 100644
index 00000000000..e93603bef36
--- /dev/null
+++ b/app/controllers/admin/deploy_keys_controller.rb
@@ -0,0 +1,49 @@
+class Admin::DeployKeysController < Admin::ApplicationController
+ before_filter :deploy_keys, only: [:index]
+ before_filter :deploy_key, only: [:show, :destroy]
+
+ def index
+
+ end
+
+ def show
+
+ end
+
+ def new
+ @deploy_key = deploy_keys.new
+ end
+
+ def create
+ @deploy_key = deploy_keys.new(deploy_key_params)
+
+ if @deploy_key.save
+ redirect_to admin_deploy_keys_path
+ else
+ render "new"
+ end
+ end
+
+ def destroy
+ deploy_key.destroy
+
+ respond_to do |format|
+ format.html { redirect_to admin_deploy_keys_path }
+ format.json { head :ok }
+ end
+ end
+
+ protected
+
+ def deploy_key
+ @deploy_key ||= deploy_keys.find(params[:id])
+ end
+
+ def deploy_keys
+ @deploy_keys ||= DeployKey.are_public
+ end
+
+ def deploy_key_params
+ params.require(:deploy_key).permit(:key, :title)
+ end
+end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 693970e5349..b4c011f213c 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -72,8 +72,8 @@ class Admin::UsersController < Admin::ApplicationController
end
respond_to do |format|
+ user.skip_reconfirmation!
if user.update_attributes(user_params_with_pass)
- user.confirm!
format.html { redirect_to [:admin, user], notice: 'User was successfully updated.' }
format.json { head :ok }
else
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 80e983b5314..0521a9ef8cf 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -153,7 +153,7 @@ class ApplicationController < ActionController::Base
end
def method_missing(method_sym, *arguments, &block)
- if method_sym.to_s =~ /^authorize_(.*)!$/
+ if method_sym.to_s =~ /\Aauthorize_(.*)!\z/
authorize_project!($1.to_sym)
else
super
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 679a5d76ec0..6fba3ce299b 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -8,7 +8,14 @@ class Projects::DeployKeysController < Projects::ApplicationController
def index
@enabled_keys = @project.deploy_keys
- @available_keys = available_keys - @enabled_keys
+
+ @available_keys = accessible_keys - @enabled_keys
+ @available_project_keys = current_user.project_deploy_keys - @enabled_keys
+ @available_public_keys = DeployKey.are_public - @enabled_keys
+
+ # Public keys that are already used by another accessible project are already
+ # in @available_project_keys.
+ @available_public_keys -= @available_project_keys
end
def show
@@ -32,18 +39,9 @@ class Projects::DeployKeysController < Projects::ApplicationController
end
end
- def destroy
- @key = @project.deploy_keys.find(params[:id])
- @key.destroy
-
- respond_to do |format|
- format.html { redirect_to namespace_project_deploy_keys_path(@project.namespace, @project) }
- format.js { render nothing: true }
- end
- end
-
def enable
- @project.deploy_keys << available_keys.find(params[:id])
+ @key = accessible_keys.find(params[:id])
+ @project.deploy_keys << @key
redirect_to namespace_project_deploy_keys_path(@project.namespace,
@project)
@@ -52,14 +50,13 @@ class Projects::DeployKeysController < Projects::ApplicationController
def disable
@project.deploy_keys_projects.find_by(deploy_key_id: params[:id]).destroy
- redirect_to namespace_project_deploy_keys_path(@project.namespace,
- @project)
+ redirect_to :back
end
protected
- def available_keys
- @available_keys ||= current_user.accessible_deploy_keys
+ def accessible_keys
+ @accessible_keys ||= current_user.accessible_deploy_keys
end
def deploy_key_params
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 7b6982c5074..3f11d7afe6f 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -26,6 +26,12 @@ class SessionsController < Devise::SessionsController
end
def create
- super
+ super do |resource|
+ # User has successfully signed in, so clear any unused reset tokens
+ if resource.reset_password_token.present?
+ resource.update_attributes(reset_password_token: nil,
+ reset_password_sent_at: nil)
+ end
+ end
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 3f3509bb18a..b5b0015542c 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -125,7 +125,7 @@ module ApplicationHelper
# If reference is commit id - we should add it to branch/tag selectbox
if(@ref && !options.flatten.include?(@ref) &&
- @ref =~ /^[0-9a-zA-Z]{6,52}$/)
+ @ref =~ /\A[0-9a-zA-Z]{6,52}\z/)
options << ['Commit', [@ref]]
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 5aae697e2f0..d13d80be293 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -134,12 +134,13 @@ module CommitsHelper
# avatar: true will prepend the avatar image
# size: size of the avatar image in px
def commit_person_link(commit, options = {})
+ user = commit.send(options[:source])
+
source_name = clean(commit.send "#{options[:source]}_name".to_sym)
source_email = clean(commit.send "#{options[:source]}_email".to_sym)
- user = User.find_for_commit(source_email, source_name)
- person_name = user.nil? ? source_name : user.name
- person_email = user.nil? ? source_email : user.email
+ person_name = user.try(:name) || source_name
+ person_email = user.try(:email) || source_email
text =
if options[:avatar]
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 17266656a4e..aa1de2f50ef 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -13,7 +13,7 @@ module GitlabMarkdownHelper
def link_to_gfm(body, url, html_options = {})
return "" if body.blank?
- escaped_body = if body =~ /^\<img/
+ escaped_body = if body =~ /\A\<img/
body
else
escape_once(body)
@@ -139,7 +139,7 @@ module GitlabMarkdownHelper
@project.path_with_namespace,
path_with_ref(file_path),
file_path
- ].compact.join("/").gsub(/^\/*|\/*$/, '') + id
+ ].compact.join("/").gsub(/\A\/*|\/*\z/, '') + id
end
def sanitize_slashes(path)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index e3734023be3..ebbd2bfd77d 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -127,6 +127,14 @@ module ProjectsHelper
html + count_html
end
+ def project_for_deploy_key(deploy_key)
+ if deploy_key.projects.include?(@project)
+ @project
+ else
+ deploy_key.projects.find { |project| can?(current_user, :read_project, project) }
+ end
+ end
+
private
def get_project_nav_tabs(project, current_user)
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
index 457cd3fa46b..54e0f4f9b3e 100644
--- a/app/helpers/selects_helper.rb
+++ b/app/helpers/selects_helper.rb
@@ -8,12 +8,14 @@ module SelectsHelper
null_user = opts[:null_user] || false
any_user = opts[:any_user] || false
+ first_user = opts[:first_user] && current_user ? current_user.username : false
html = {
class: css_class,
'data-placeholder' => placeholder,
'data-null-user' => null_user,
'data-any-user' => any_user,
+ 'data-first-user' => first_user
}
unless opts[:scope] == :all
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
index 241462e5e4c..9954617c762 100644
--- a/app/helpers/submodule_helper.rb
+++ b/app/helpers/submodule_helper.rb
@@ -44,7 +44,7 @@ module SubmoduleHelper
def relative_self_url?(url)
# (./)?(../repo.git) || (./)?(../../project/repo.git) )
- url =~ /^((\.\/)?(\.\.\/))(?!(\.\.)|(.*\/)).*\.git\Z/ || url =~ /^((\.\/)?(\.\.\/){2})(?!(\.\.))([^\/]*)\/(?!(\.\.)|(.*\/)).*\.git\Z/
+ url =~ /\A((\.\/)?(\.\.\/))(?!(\.\.)|(.*\/)).*\.git\z/ || url =~ /\A((\.\/)?(\.\.\/){2})(?!(\.\.))([^\/]*)\/(?!(\.\.)|(.*\/)).*\.git\z/
end
def standard_links(host, namespace, project, commit)
@@ -53,15 +53,22 @@ module SubmoduleHelper
end
def relative_self_links(url, commit)
- if url.scan(/(\.\.\/)/).size == 2
- base = url[/([^\/]*\/[^\/]*)\.git/, 1]
- else
- base = [ @project.group.path, '/', url[/([^\/]*)\.git/, 1] ].join('')
+ # Map relative links to a namespace and project
+ # For example:
+ # ../bar.git -> same namespace, repo bar
+ # ../foo/bar.git -> namespace foo, repo bar
+ # ../../foo/bar/baz.git -> namespace bar, repo baz
+ components = url.split('/')
+ base = components.pop.gsub(/.git$/, '')
+ namespace = components.pop.gsub(/^\.\.$/, '')
+
+ if namespace.empty?
+ namespace = @project.group.path
end
[
- namespace_project_path(base.namespace, base),
- namespace_project_tree_path(base.namespace, base, commit)
+ namespace_project_path(namespace, base),
+ namespace_project_tree_path(namespace, base, commit)
]
end
end
diff --git a/app/mailers/emails/groups.rb b/app/mailers/emails/groups.rb
index 26f43bf955e..626eb593d51 100644
--- a/app/mailers/emails/groups.rb
+++ b/app/mailers/emails/groups.rb
@@ -4,6 +4,7 @@ module Emails
@group_member = GroupMember.find(group_member_id)
@group = @group_member.group
@target_url = group_url(@group)
+ @current_user = @group_member.user
mail(to: @group_member.user.email,
subject: subject("Access to group was granted"))
end
diff --git a/app/mailers/emails/profile.rb b/app/mailers/emails/profile.rb
index ab5b0765352..3a83b083109 100644
--- a/app/mailers/emails/profile.rb
+++ b/app/mailers/emails/profile.rb
@@ -1,7 +1,7 @@
module Emails
module Profile
def new_user_email(user_id, token = nil)
- @user = User.find(user_id)
+ @current_user = @user = User.find(user_id)
@target_url = user_url(@user)
@token = token
mail(to: @user.notification_email, subject: subject("Account was created for you"))
@@ -9,13 +9,13 @@ module Emails
def new_email_email(email_id)
@email = Email.find(email_id)
- @user = @email.user
+ @current_user = @user = @email.user
mail(to: @user.notification_email, subject: subject("Email was added to your account"))
end
def new_ssh_key_email(key_id)
@key = Key.find(key_id)
- @user = @key.user
+ @current_user = @user = @key.user
@target_url = user_url(@user)
mail(to: @user.notification_email, subject: subject("SSH key was added to your account"))
end
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index 3cd812825e2..20a863c3742 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -4,12 +4,13 @@ module Emails
@project_member = ProjectMember.find user_project_id
@project = @project_member.project
@target_url = namespace_project_url(@project.namespace, @project)
+ @current_user = @project_member.user
mail(to: @project_member.user.email,
subject: subject("Access to project was granted"))
end
def project_was_moved_email(project_id, user_id)
- @user = User.find user_id
+ @current_user = @user = User.find user_id
@project = Project.find project_id
@target_url = namespace_project_url(@project.namespace, @project)
mail(to: @user.notification_email,
@@ -28,7 +29,7 @@ module Emails
end
@project = Project.find(project_id)
- @author = User.find(author_id)
+ @current_user = @author = User.find(author_id)
@reverse_compare = reverse_compare
@compare = compare
@ref_name = Gitlab::Git.ref_name(ref)
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 0c186ab5866..7c8b37029d1 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -13,6 +13,9 @@ class Notify < ActionMailer::Base
add_template_helper MergeRequestsHelper
add_template_helper EmailsHelper
+ attr_accessor :current_user
+ helper_method :current_user, :can?
+
default_url_options[:host] = Gitlab.config.gitlab.host
default_url_options[:protocol] = Gitlab.config.gitlab.protocol
default_url_options[:port] = Gitlab.config.gitlab.port unless Gitlab.config.gitlab_on_standard_port?
@@ -79,9 +82,8 @@ class Notify < ActionMailer::Base
#
# Returns a String containing the User's email address.
def recipient(recipient_id)
- if recipient = User.find(recipient_id)
- recipient.notification_email
- end
+ @current_user = User.find(recipient_id)
+ @current_user.notification_email
end
# Set the References header field
@@ -154,4 +156,8 @@ class Notify < ActionMailer::Base
mail(headers, &block)
end
+
+ def can?
+ Ability.abilities.allowed?(user, action, subject)
+ end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 6e98c4c2f02..0d8365c4ff2 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -24,7 +24,7 @@ class ApplicationSetting < ActiveRecord::Base
validates :home_page_url,
allow_blank: true,
- format: { with: URI::regexp(%w(http https)), message: "should be a valid url" },
+ format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" },
if: :home_page_url_column_exist
validates_each :restricted_visibility_levels do |record, attr, value|
diff --git a/app/models/commit.rb b/app/models/commit.rb
index e0461809e10..7a0ad137650 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -117,8 +117,8 @@ class Commit
# Discover issues should be closed when this commit is pushed to a project's
# default branch.
- def closes_issues(project)
- Gitlab::ClosingIssueExtractor.closed_by_message_in_project(safe_message, project)
+ def closes_issues(project, current_user = self.committer)
+ Gitlab::ClosingIssueExtractor.new(project, current_user).closed_by_message(safe_message)
end
# Mentionable override.
@@ -126,6 +126,14 @@ class Commit
"commit #{id}"
end
+ def author
+ User.find_for_commit(author_email, author_name)
+ end
+
+ def committer
+ User.find_for_commit(committer_email, committer_name)
+ end
+
def method_missing(m, *args, &block)
@raw.send(m, *args, &block)
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 88ac83744df..478134dff68 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -118,16 +118,16 @@ module Issuable
end
# Return all users participating on the discussion
- def participants
+ def participants(current_user = self.author)
users = []
users << author
users << assignee if is_assigned?
mentions = []
- mentions << self.mentioned_users
+ mentions << self.mentioned_users(current_user)
notes.each do |note|
users << note.author
- mentions << note.mentioned_users
+ mentions << note.mentioned_users(current_user)
end
users.concat(mentions.reduce([], :|)).uniq
@@ -140,7 +140,7 @@ module Issuable
return subscription.subscribed
end
- participants.include?(user)
+ participants(user).include?(user)
end
def toggle_subscription(user)
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index d96e07034ec..b7882a2bb16 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -42,35 +42,22 @@ module Mentionable
Note.cross_reference_exists?(target, local_reference)
end
- def mentioned_users
- users = []
- return users if mentionable_text.blank?
- has_project = self.respond_to? :project
- matches = mentionable_text.scan(/@[a-zA-Z][a-zA-Z0-9_\-\.]*/)
- matches.each do |match|
- identifier = match.delete "@"
- if identifier == "all"
- users.push(*project.team.members.flatten)
- elsif namespace = Namespace.find_by(path: identifier)
- if namespace.is_a?(Group)
- users.push(*namespace.users)
- else
- users << namespace.owner
- end
- end
- end
- users.uniq
+ def mentioned_users(current_user = nil)
+ return [] if mentionable_text.blank?
+
+ ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
+ ext.analyze(mentionable_text)
+ ext.users.uniq
end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
- def references(p = project, text = mentionable_text)
+ def references(p = project, current_user = self.author, text = mentionable_text)
return [] if text.blank?
- ext = Gitlab::ReferenceExtractor.new
- ext.analyze(text, p)
- (ext.issues_for(p) +
- ext.merge_requests_for(p) +
- ext.commits_for(p)).uniq - [local_reference]
+ ext = Gitlab::ReferenceExtractor.new(p, current_user)
+ ext.analyze(text)
+
+ (ext.issues + ext.merge_requests + ext.commits).uniq - [local_reference]
end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
@@ -96,7 +83,7 @@ module Mentionable
# Only proceed if the saved changes actually include a chance to an attr_mentionable field.
return unless mentionable_changed
- preexisting = references(p, original)
+ preexisting = references(p, self.author, original)
create_cross_references!(p, a, preexisting)
end
end
diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb
index 570f5e91c13..85d52d558cd 100644
--- a/app/models/deploy_key.rb
+++ b/app/models/deploy_key.rb
@@ -7,6 +7,7 @@
# created_at :datetime
# updated_at :datetime
# key :text
+# public :boolean default(FALSE)
# title :string(255)
# type :string(255)
# fingerprint :string(255)
@@ -17,4 +18,21 @@ class DeployKey < Key
has_many :projects, through: :deploy_keys_projects
scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) }
+ scope :are_public, -> { where(public: true) }
+
+ def private?
+ !public?
+ end
+
+ def orphaned?
+ self.deploy_keys_projects.length == 0
+ end
+
+ def almost_orphaned?
+ self.deploy_keys_projects.length == 1
+ end
+
+ def destroyed_when_orphaned?
+ self.private?
+ end
end
diff --git a/app/models/deploy_keys_project.rb b/app/models/deploy_keys_project.rb
index 7e88903b9af..18db521741f 100644
--- a/app/models/deploy_keys_project.rb
+++ b/app/models/deploy_keys_project.rb
@@ -22,6 +22,8 @@ class DeployKeysProject < ActiveRecord::Base
private
def destroy_orphaned_deploy_key
- self.deploy_key.destroy if self.deploy_key.deploy_keys_projects.length == 0
+ return unless self.deploy_key.destroyed_when_orphaned? && self.deploy_key.orphaned?
+
+ self.deploy_key.destroy
end
end
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index defef7216f2..315d96af1b9 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -28,7 +28,7 @@ class WebHook < ActiveRecord::Base
default_timeout Gitlab.config.gitlab.webhook_timeout
validates :url, presence: true,
- format: { with: URI::regexp(%w(http https)), message: "should be a valid url" }
+ format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }
def execute(data)
parsed_url = URI.parse(url)
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 5634f9a686e..35cb920d8bc 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -257,11 +257,11 @@ class MergeRequest < ActiveRecord::Base
end
# Return the set of issues that will be closed if this merge request is accepted.
- def closes_issues
+ def closes_issues(current_user = self.author)
if target_branch == project.default_branch
- issues = commits.flat_map { |c| c.closes_issues(project) }
- issues.push(*Gitlab::ClosingIssueExtractor.
- closed_by_message_in_project(description, project))
+ issues = commits.flat_map { |c| c.closes_issues(project, current_user) }
+ issues.push(*Gitlab::ClosingIssueExtractor.new(project, current_user).
+ closed_by_message(description))
issues.uniq.sort_by(&:id)
else
[]
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index dd74165f887..a0d79d7e5c0 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -61,8 +61,8 @@ class Namespace < ActiveRecord::Base
def clean_path(path)
path.gsub!(/@.*\z/, "")
path.gsub!(/\.git\z/, "")
- path.gsub!(/\A-/, "")
- path.gsub!(/.\z/, "")
+ path.gsub!(/\A-+/, "")
+ path.gsub!(/\.+\z/, "")
path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
counter = 0
diff --git a/app/models/project.rb b/app/models/project.rb
index 79572f255db..dcbafd76475 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -81,7 +81,7 @@ class Project < ActiveRecord::Base
has_one :asana_service, dependent: :destroy
has_one :gemnasium_service, dependent: :destroy
has_one :slack_service, dependent: :destroy
- has_one :buildbox_service, dependent: :destroy
+ has_one :buildkite_service, dependent: :destroy
has_one :bamboo_service, dependent: :destroy
has_one :teamcity_service, dependent: :destroy
has_one :pushover_service, dependent: :destroy
@@ -137,7 +137,7 @@ class Project < ActiveRecord::Base
validates_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id
validates :import_url,
- format: { with: URI::regexp(%w(ssh git http https)), message: 'should be a valid url' },
+ format: { with: /\A#{URI.regexp(%w(ssh git http https))}\z/, message: 'should be a valid url' },
if: :import?
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index f968afe9fa8..d8aedbd2ab4 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -25,7 +25,7 @@ class BambooService < CiService
validates :bamboo_url,
presence: true,
- format: { with: URI::regexp },
+ format: { with: /\A#{URI.regexp}\z/ },
if: :activated?
validates :build_key, presence: true, if: :activated?
validates :username,
diff --git a/app/models/project_services/buildbox_service.rb b/app/models/project_services/buildkite_service.rb
index 3a381ff11b8..a714bc82246 100644
--- a/app/models/project_services/buildbox_service.rb
+++ b/app/models/project_services/buildkite_service.rb
@@ -20,9 +20,7 @@
require "addressable/uri"
-# Buildbox renamed to Buildkite, but for backwards compatability with the STI
-# of Services, the class name is kept as "Buildbox"
-class BuildboxService < CiService
+class BuildkiteService < CiService
ENDPOINT = "https://buildkite.com"
prop_accessor :project_url, :token
diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb
index e521186798c..a199d0e86f2 100644
--- a/app/models/project_services/external_wiki_service.rb
+++ b/app/models/project_services/external_wiki_service.rb
@@ -18,7 +18,7 @@ class ExternalWikiService < Service
prop_accessor :external_wiki_url
validates :external_wiki_url,
presence: true,
- format: { with: URI::regexp },
+ format: { with: /\A#{URI.regexp}\z/ },
if: :activated?
def title
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index edaeeffc228..0f9838a575d 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -18,6 +18,8 @@
#
class GitlabCiService < CiService
+ API_PREFIX = "api/v1"
+
prop_accessor :project_url, :token
validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
@@ -59,6 +61,26 @@ class GitlabCiService < CiService
end
end
+ def fork_registration(new_project, private_token)
+ params = {
+ id: new_project.id,
+ name_with_namespace: new_project.name_with_namespace,
+ web_url: new_project.web_url,
+ default_branch: new_project.default_branch,
+ ssh_url_to_repo: new_project.ssh_url_to_repo
+ }
+
+ HTTParty.post(
+ fork_registration_path,
+ body: {
+ project_id: project.id,
+ project_token: token,
+ private_token: private_token,
+ data: params },
+ verify: false
+ )
+ end
+
def commit_coverage(sha, ref)
response = get_ci_build(sha, ref)
@@ -97,4 +119,10 @@ class GitlabCiService < CiService
{ type: 'text', name: 'project_url', placeholder: 'http://ci.gitlabhq.com/projects/3' }
]
end
+
+ private
+
+ def fork_registration_path
+ project_url.sub(/projects\/\d*/, "#{API_PREFIX}/forks")
+ end
end
diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb
index 2bddb7b881c..e9e1e276e7d 100644
--- a/app/models/project_services/irker_service.rb
+++ b/app/models/project_services/irker_service.rb
@@ -148,7 +148,7 @@ class IrkerService < Service
def consider_uri(uri)
# Authorize both irc://domain.com/#chan and irc://domain.com/chan
- if uri.is_a?(URI) && uri.scheme[/^ircs?$/] && !uri.path.nil?
+ if uri.is_a?(URI) && uri.scheme[/^ircs?\z/] && !uri.path.nil?
# Do not authorize irc://domain.com/
if uri.fragment.nil? && uri.path.length > 1
uri.to_s
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index c26bc551352..3c002a1634b 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -25,7 +25,7 @@ class TeamcityService < CiService
validates :teamcity_url,
presence: true,
- format: { with: URI::regexp }, if: :activated?
+ format: { with: /\A#{URI.regexp}\z/ }, if: :activated?
validates :build_type, presence: true, if: :activated?
validates :username,
presence: true,
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 72769498872..263a436d521 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -199,7 +199,7 @@ class Repository
def changelog
cache.fetch(:changelog) do
tree(:head).blobs.find do |file|
- file.name =~ /^(changelog|history)/i
+ file.name =~ /\A(changelog|history)/i
end
end
end
@@ -207,7 +207,7 @@ class Repository
def license
cache.fetch(:license) do
tree(:head).blobs.find do |file|
- file.name =~ /^license/i
+ file.name =~ /\Alicense/i
end
end
end
diff --git a/app/models/service.rb b/app/models/service.rb
index f54ad19666b..393cf55a69f 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -122,25 +122,25 @@ class Service < ActiveRecord::Base
def self.available_services_names
%w(
- gitlab_ci
- campfire
- hipchat
- pivotaltracker
- flowdock
- assembla
asana
+ assembla
+ bamboo
+ buildkite
+ campfire
+ custom_issue_tracker
emails_on_push
+ external_wiki
+ flowdock
gemnasium
- slack
- pushover
- buildbox
- bamboo
- teamcity
+ gitlab_ci
+ hipchat
+ irker
jira
+ pivotaltracker
+ pushover
redmine
- custom_issue_tracker
- irker
- external_wiki
+ slack
+ teamcity
)
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 515f29ea0ba..a40111e62dd 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -414,8 +414,16 @@ class User < ActiveRecord::Base
@ldap_identity ||= identities.find_by(["provider LIKE ?", "ldap%"])
end
+ def project_deploy_keys
+ DeployKey.in_projects(self.authorized_projects.pluck(:id))
+ end
+
def accessible_deploy_keys
- DeployKey.in_projects(self.authorized_projects.pluck(:id)).uniq
+ @accessible_deploy_keys ||= begin
+ key_ids = project_deploy_keys.pluck(:id)
+ key_ids.push(*DeployKey.are_public.pluck(:id))
+ DeployKey.where(id: key_ids)
+ end
end
def created_by
@@ -486,13 +494,13 @@ class User < ActiveRecord::Base
end
def full_website_url
- return "http://#{website_url}" if website_url !~ /^https?:\/\//
+ return "http://#{website_url}" if website_url !~ /\Ahttps?:\/\//
website_url
end
def short_website_url
- website_url.gsub(/https?:\/\//, '')
+ website_url.sub(/\Ahttps?:\/\//, '')
end
def all_ssh_keys
diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb
index 4115d689925..25f9e203246 100644
--- a/app/services/create_tag_service.rb
+++ b/app/services/create_tag_service.rb
@@ -13,9 +13,7 @@ class CreateTagService < BaseService
return error('Tag already exists')
end
- if message
- message.gsub!(/^\s+|\s+$/, '')
- end
+ message.strip! if message
repository.add_tag(tag_name, ref, message)
new_tag = repository.find_tag(tag_name)
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 1f0b29dff5e..31e0167d247 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -70,7 +70,7 @@ class GitPushService
# Close issues if these commits were pushed to the project's default branch and the commit message matches the
# closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
# a different branch.
- issues_to_close = commit.closes_issues(project)
+ issues_to_close = commit.closes_issues(project, user)
# Load commit author only if needed.
# For push with 1k commits it prevents 900+ requests in database
@@ -87,7 +87,7 @@ class GitPushService
# Create cross-reference notes for any other references. Omit any issues that were referenced in an
# issue-closing phrase, or have already been mentioned from this commit (probably from this commit
# being pushed to a different branch).
- refs = commit.references(project) - issues_to_close
+ refs = commit.references(project, user) - issues_to_close
refs.reject! { |r| commit.has_mentioned?(r) }
if refs.present?
@@ -127,6 +127,6 @@ class GitPushService
end
def commit_user(commit)
- User.find_for_commit(commit.author_email, commit.author_name) || user
+ commit.author || user
end
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index cc5853144c5..42547f6f481 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -123,32 +123,29 @@ class NotificationService
return true if note.note.start_with?('Status changed to closed')
return true if note.cross_reference? && note.system == true
- opts = { noteable_type: note.noteable_type, project_id: note.project_id }
-
target = note.noteable
- if target.respond_to?(:participants)
- recipients = target.participants
- else
- recipients = note.mentioned_users
- end
+ recipients = []
if note.commit_id.present?
- opts.merge!(commit_id: note.commit_id)
recipients << note.commit_author
- else
- opts.merge!(noteable_id: note.noteable_id)
end
# Get users who left comment in thread
- recipients = recipients.concat(User.where(id: Note.where(opts).pluck(:author_id)))
+ recipients = recipients.concat(noteable_commenters(note))
# Merge project watchers
recipients = recipients.concat(project_watchers(note.project)).compact.uniq
- # Reject mention users unless mentioned in comment
- recipients = reject_mention_users(recipients - note.mentioned_users, note.project)
- recipients = recipients + note.mentioned_users
+ # Reject users with Mention notification level
+ recipients = reject_mention_users(recipients, note.project)
+
+ # Add explicitly mentioned users
+ if target.respond_to?(:participants)
+ recipients = recipients.concat(target.participants)
+ else
+ recipients = recipients.concat(note.mentioned_users)
+ end
# Reject mutes users
recipients = reject_muted_users(recipients, note.project)
@@ -195,6 +192,18 @@ class NotificationService
protected
+ def noteable_commenters(note)
+ opts = { noteable_type: note.noteable_type, project_id: note.project_id }
+
+ if note.commit_id.present?
+ opts.merge!(commit_id: note.commit_id)
+ else
+ opts.merge!(noteable_id: note.noteable_id)
+ end
+
+ User.where(id: Note.where(opts).pluck(:author_id))
+ end
+
# Get project users with WATCH notification level
def project_watchers(project)
project_members = project_member_notification(project)
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 6b0d4aca3e1..4ec98696a65 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -40,12 +40,18 @@ module Projects
if project.save
project.team << [@current_user, :master]
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
+
+ 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
diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb
index bcbacbff562..ae6260bcdab 100644
--- a/app/services/projects/participants_service.rb
+++ b/app/services/projects/participants_service.rb
@@ -1,10 +1,5 @@
module Projects
class ParticipantsService < BaseService
- def initialize(project, user)
- @project = project
- @user = user
- end
-
def execute(note_type, note_id)
participating =
if note_type && note_id
@@ -12,7 +7,7 @@ module Projects
else
[]
end
- project_members = sorted(@project.team.members)
+ project_members = sorted(project.team.members)
participants = all_members + groups + project_members + participating
participants.uniq
end
@@ -20,11 +15,11 @@ module Projects
def participants_in(type, id)
users = case type
when "Issue"
- issue = @project.issues.find_by_iid(id)
- issue ? issue.participants : []
+ issue = project.issues.find_by_iid(id)
+ issue ? issue.participants(current_user) : []
when "MergeRequest"
- merge_request = @project.merge_requests.find_by_iid(id)
- merge_request ? merge_request.participants : []
+ merge_request = project.merge_requests.find_by_iid(id)
+ merge_request ? merge_request.participants(current_user) : []
when "Commit"
author_ids = Note.for_commit_id(id).pluck(:author_id).uniq
User.where(id: author_ids)
@@ -41,14 +36,14 @@ module Projects
end
def groups
- @user.authorized_groups.sort_by(&:path).map do |group|
+ current_user.authorized_groups.sort_by(&:path).map do |group|
count = group.users.count
{ username: group.path, name: "#{group.name} (#{count})" }
end
end
def all_members
- count = @project.team.members.flatten.count
+ count = project.team.members.flatten.count
[{ username: "all", name: "All Project and Group Members (#{count})" }]
end
end
diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml
new file mode 100644
index 00000000000..2ae83ab95f7
--- /dev/null
+++ b/app/views/admin/deploy_keys/index.html.haml
@@ -0,0 +1,27 @@
+.panel.panel-default
+ .panel-heading
+ Public deploy keys (#{@deploy_keys.count})
+ .panel-head-actions
+ = link_to 'New Deploy Key', new_admin_deploy_key_path, class: "btn btn-new btn-sm"
+ - if @deploy_keys.any?
+ %table.table
+ %thead.panel-heading
+ %tr
+ %th Title
+ %th Fingerprint
+ %th Added at
+ %th
+ %tbody
+ - @deploy_keys.each do |deploy_key|
+ %tr
+ %td
+ = link_to admin_deploy_key_path(deploy_key) do
+ %strong= deploy_key.title
+ %td
+ %span
+ (#{deploy_key.fingerprint})
+ %td
+ %span.cgray
+ added #{time_ago_with_tooltip(deploy_key.created_at)}
+ %td
+ = link_to 'Remove', admin_deploy_key_path(deploy_key), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-sm btn-remove delete-key pull-right"
diff --git a/app/views/admin/deploy_keys/new.html.haml b/app/views/admin/deploy_keys/new.html.haml
new file mode 100644
index 00000000000..c00049424c5
--- /dev/null
+++ b/app/views/admin/deploy_keys/new.html.haml
@@ -0,0 +1,26 @@
+%h3.page-title New public deploy key
+%hr
+
+%div
+ = form_for [:admin, @deploy_key], html: { class: 'deploy-key-form form-horizontal' } do |f|
+ -if @deploy_key.errors.any?
+ .alert.alert-danger
+ %ul
+ - @deploy_key.errors.full_messages.each do |msg|
+ %li= msg
+
+ .form-group
+ = f.label :title, class: "control-label"
+ .col-sm-10= f.text_field :title, class: 'form-control'
+ .form-group
+ = f.label :key, class: "control-label"
+ .col-sm-10
+ %p.light
+ Paste a machine public key here. Read more about how to generate it
+ = link_to "here", help_page_path("ssh", "README")
+ = f.text_area :key, class: "form-control thin_area", rows: 5
+
+ .form-actions
+ = f.submit 'Create', class: "btn-create btn"
+ = link_to "Cancel", admin_deploy_keys_path, class: "btn btn-cancel"
+
diff --git a/app/views/admin/deploy_keys/show.html.haml b/app/views/admin/deploy_keys/show.html.haml
new file mode 100644
index 00000000000..cfa2adf92ee
--- /dev/null
+++ b/app/views/admin/deploy_keys/show.html.haml
@@ -0,0 +1,34 @@
+.row
+ .col-md-4
+ .panel.panel-default
+ .panel-heading
+ Deploy Key
+ %ul.well-list
+ %li
+ %span.light Title:
+ %strong= @deploy_key.title
+ %li
+ %span.light Created on:
+ %strong= @deploy_key.created_at.stamp("Aug 21, 2011")
+
+ .panel.panel-default
+ .panel-heading Projects (#{@deploy_key.deploy_keys_projects.count})
+ - if @deploy_key.deploy_keys_projects.any?
+ %ul.well-list
+ - @deploy_key.projects.each do |project|
+ %li
+ %span
+ %strong
+ = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project]
+ .pull-right
+ = link_to disable_namespace_project_deploy_key_path(project.namespace, project, @deploy_key), data: { confirm: "Are you sure?" }, method: :put, class: "btn-xs btn btn-remove", title: 'Remove deploy key from project' do
+ %i.fa.fa-times.fa-inverse
+
+ .col-md-8
+ %p
+ %span.light Fingerprint:
+ %strong= @deploy_key.fingerprint
+ %pre.well-pre
+ = @deploy_key.key
+ .pull-right
+ = link_to 'Remove', admin_deploy_key_path(@deploy_key), data: {confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove delete-key"
diff --git a/app/views/dashboard/projects/starred.html.haml b/app/views/dashboard/projects/starred.html.haml
index 670f5ac7af7..f4ad2b294b3 100644
--- a/app/views/dashboard/projects/starred.html.haml
+++ b/app/views/dashboard/projects/starred.html.haml
@@ -19,5 +19,5 @@
%i.fa.fa-angle-left
- else
- %h3 You dont have starred projects yet
+ %h3 You don't have starred projects yet
%p.slead Visit project page and press on star icon and it will appear on this page.
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index 2f38d596c65..34efceb37d1 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -19,6 +19,11 @@
%i.fa.fa-group
%span
Groups
+ = nav_link(controller: :deploy_keys) do
+ = link_to admin_deploy_keys_path, title: 'Deploy Keys' do
+ %i.fa.fa-key
+ %span
+ Deploy Keys
= nav_link(controller: :logs) do
= link_to admin_logs_path, title: 'Logs' do
%i.fa.fa-file-text
diff --git a/app/views/projects/deploy_keys/_deploy_key.html.haml b/app/views/projects/deploy_keys/_deploy_key.html.haml
index a2faa9d5e25..c577dfa8d55 100644
--- a/app/views/projects/deploy_keys/_deploy_key.html.haml
+++ b/app/views/projects/deploy_keys/_deploy_key.html.haml
@@ -5,21 +5,32 @@
%i.fa.fa-plus
Enable
- else
- - if deploy_key.projects.count > 1
+ - if deploy_key.destroyed_when_orphaned? && deploy_key.almost_orphaned?
+ = link_to 'Remove', disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :put, class: "btn btn-remove delete-key btn-sm pull-right"
+ - else
= link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do
%i.fa.fa-power-off
Disable
- - else
- = link_to 'Remove', namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :delete, class: "btn btn-remove delete-key btn-sm pull-right"
-
- - key_project = deploy_key.projects.include?(@project) ? @project : deploy_key.projects.first
- = link_to namespace_project_deploy_key_path(key_project.namespace, key_project, deploy_key) do
+ - if project = project_for_deploy_key(deploy_key)
+ = link_to namespace_project_deploy_key_path(project.namespace, project, deploy_key) do
+ %i.fa.fa-key
+ %strong= deploy_key.title
+ - else
%i.fa.fa-key
%strong= deploy_key.title
+
%p.light.prepend-top-10
- - deploy_key.projects.map(&:name_with_namespace).each do |project_name|
- %span.label.label-gray.deploy-project-label= project_name
+ - if deploy_key.public?
+ %span.label.label-info.deploy-project-label
+ Public deploy key
+
+ - deploy_key.projects.each do |project|
+ - if can?(current_user, :read_project, project)
+ %span.label.label-gray.deploy-project-label
+ = link_to namespace_project_path(project.namespace, project) do
+ = project.name_with_namespace
+
%small.pull-right
Created #{time_ago_with_tooltip(deploy_key.created_at)}
diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml
index c02a18146eb..472a13a8524 100644
--- a/app/views/projects/deploy_keys/index.html.haml
+++ b/app/views/projects/deploy_keys/index.html.haml
@@ -22,11 +22,20 @@
.light-well
.nothing-here-block Create a #{link_to 'new deploy key', new_namespace_project_deploy_key_path(@project.namespace, @project)} or add an existing one
.col-md-6.available-keys
- %h5
- %strong Deploy keys
- from projects available to you
- %ul.bordered-list
- = render @available_keys
- - if @available_keys.blank?
- .light-well
- .nothing-here-block Deploy keys from projects you have access to will be displayed here
+ - # If there are available public deploy keys but no available project deploy keys, only public deploy keys are shown.
+ - if @available_project_keys.any? || @available_public_keys.blank?
+ %h5
+ %strong Deploy keys
+ from projects you have access to
+ %ul.bordered-list
+ = render @available_project_keys
+ - if @available_project_keys.blank?
+ .light-well
+ .nothing-here-block Deploy keys from projects you have access to will be displayed here
+
+ - if @available_public_keys.any?
+ %h5
+ %strong Public deploy keys
+ available to any project
+ %ul.bordered-list
+ = render @available_public_keys
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 2b9b6599a7d..b49aee504fe 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -20,4 +20,4 @@
Maybe diff is really big and operation failed with timeout. Try to get diff locally
:coffeescript
- $('.files .diff-header').stick_in_parent(recalc_every: 1, offset_top: $('.navbar').height())
+ $('.files .diff-header').stick_in_parent(offset_top: $('.navbar').height())
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index 0d3028d50b4..288b48f4583 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -9,8 +9,8 @@
.votes-holder.pull-right
#votes= render 'votes/votes_block', votable: @issue
.participants
- %span= pluralize(@issue.participants.count, 'participant')
- - @issue.participants.each do |participant|
+ %span= pluralize(@issue.participants(current_user).count, 'participant')
+ - @issue.participants(current_user).each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
.voting_notes#notes= render "projects/notes/notes_with_form"
%aside.col-md-3
diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml
index 52e38050419..9228074d833 100644
--- a/app/views/projects/issues/_issue_context.html.haml
+++ b/app/views/projects/issues/_issue_context.html.haml
@@ -8,7 +8,7 @@
- else
none
- if can?(current_user, :modify_issue, @issue)
- = users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id, null_user: true)
+ = users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id, null_user: true, first_user: true)
%div.prepend-top-20.clearfix
.issuable-context-title
diff --git a/app/views/projects/merge_requests/show/_participants.html.haml b/app/views/projects/merge_requests/show/_participants.html.haml
index 4f34af1737d..9c93fa55fe6 100644
--- a/app/views/projects/merge_requests/show/_participants.html.haml
+++ b/app/views/projects/merge_requests/show/_participants.html.haml
@@ -1,4 +1,4 @@
.participants
- %span #{@merge_request.participants.count} participants
- - @merge_request.participants.each do |participant|
+ %span #{@merge_request.participants(current_user).count} participants
+ - @merge_request.participants(current_user).each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
diff --git a/app/views/shared/_issuable_filter.html.haml b/app/views/shared/_issuable_filter.html.haml
index f169733f2e9..83f5a3a8015 100644
--- a/app/views/shared/_issuable_filter.html.haml
+++ b/app/views/shared/_issuable_filter.html.haml
@@ -24,11 +24,11 @@
.issues-other-filters
.filter-item.inline
= users_select_tag(:assignee_id, selected: params[:assignee_id],
- placeholder: 'Assignee', class: 'trigger-submit', any_user: true, null_user: true)
+ placeholder: 'Assignee', class: 'trigger-submit', any_user: true, null_user: true, first_user: true)
.filter-item.inline
= users_select_tag(:author_id, selected: params[:author_id],
- placeholder: 'Author', class: 'trigger-submit', any_user: true)
+ placeholder: 'Author', class: 'trigger-submit', any_user: true, first_user: true)
.filter-item.inline.milestone-filter
= select_tag('milestone_id', projects_milestones_options, class: "select2 trigger-submit", prompt: 'Milestone')
diff --git a/app/views/shared/_project.html.haml b/app/views/shared/_project.html.haml
index 8746970c239..722a7f7ce0f 100644
--- a/app/views/shared/_project.html.haml
+++ b/app/views/shared/_project.html.haml
@@ -1,4 +1,4 @@
-= cache [project, controller.controller_name, controller.action_name] do
+= cache [project.namespace, project, controller.controller_name, controller.action_name] do
= link_to project_path(project), class: dom_class(project) do
- if avatar
.dash-project-avatar
diff --git a/app/workers/fork_registration_worker.rb b/app/workers/fork_registration_worker.rb
new file mode 100644
index 00000000000..fffa8b3a659
--- /dev/null
+++ b/app/workers/fork_registration_worker.rb
@@ -0,0 +1,12 @@
+class ForkRegistrationWorker
+ include Sidekiq::Worker
+
+ sidekiq_options queue: :default
+
+ def perform(from_project_id, to_project_id, private_token)
+ from_project = Project.find(from_project_id)
+ to_project = Project.find(to_project_id)
+
+ from_project.gitlab_ci_service.fork_registration(to_project, private_token)
+ end
+end
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 0c3ee6ba4ff..33d8cc8861b 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -11,8 +11,8 @@ class PostReceive
log("Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"")
end
- repo_path.gsub!(/\.git$/, "")
- repo_path.gsub!(/^\//, "")
+ repo_path.gsub!(/\.git\z/, "")
+ repo_path.gsub!(/\A\//, "")
project = Project.find_with_namespace(repo_path)
diff --git a/config/initializers/5_backend.rb b/config/initializers/5_backend.rb
index 7c2e7f39000..80d641d73a3 100644
--- a/config/initializers/5_backend.rb
+++ b/config/initializers/5_backend.rb
@@ -6,3 +6,10 @@ require Rails.root.join("lib", "gitlab", "backend", "shell")
# GitLab shell adapter
require Rails.root.join("lib", "gitlab", "backend", "shell_adapter")
+
+required_version = Gitlab::VersionInfo.parse(Gitlab::Shell.version_required)
+current_version = Gitlab::VersionInfo.parse(Gitlab::Shell.new.version)
+
+unless current_version.valid? && required_version <= current_version
+ warn "WARNING: This version of GitLab depends on gitlab-shell #{required_version}, but you're running #{current_version}. Please update gitlab-shell."
+end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 79abe3c695d..9dce495106f 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -208,7 +208,7 @@ Devise.setup do |config|
if Gitlab::LDAP::Config.enabled?
Gitlab.config.ldap.servers.values.each do |server|
if server['allow_username_or_email_login']
- email_stripping_proc = ->(name) {name.gsub(/@.*$/,'')}
+ email_stripping_proc = ->(name) {name.gsub(/@.*\z/,'')}
else
email_stripping_proc = ->(name) {name}
end
diff --git a/config/routes.rb b/config/routes.rb
index c1b85b025b5..de21f418329 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -145,6 +145,8 @@ Gitlab::Application.routes.draw do
end
end
+ resources :deploy_keys, only: [:index, :show, :new, :create, :destroy]
+
resources :hooks, only: [:index, :create, :destroy] do
get :test
end
@@ -393,7 +395,7 @@ Gitlab::Application.routes.draw do
end
end
- resources :deploy_keys, constraints: { id: /\d+/ } do
+ resources :deploy_keys, constraints: { id: /\d+/ }, only: [:index, :show, :new, :create] do
member do
put :enable
put :disable
diff --git a/db/migrate/20150327122227_add_public_to_key.rb b/db/migrate/20150327122227_add_public_to_key.rb
new file mode 100644
index 00000000000..6ffbf4cda19
--- /dev/null
+++ b/db/migrate/20150327122227_add_public_to_key.rb
@@ -0,0 +1,5 @@
+class AddPublicToKey < ActiveRecord::Migration
+ def change
+ add_column :keys, :public, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20150411180045_rename_buildbox_service.rb b/db/migrate/20150411180045_rename_buildbox_service.rb
new file mode 100644
index 00000000000..5a0b5d07e50
--- /dev/null
+++ b/db/migrate/20150411180045_rename_buildbox_service.rb
@@ -0,0 +1,9 @@
+class RenameBuildboxService < ActiveRecord::Migration
+ def up
+ execute "UPDATE services SET type = 'BuildkiteService' WHERE type = 'BuildboxService';"
+ end
+
+ def down
+ execute "UPDATE services SET type = 'BuildboxService' WHERE type = 'BuildkiteService';"
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 903ed161e4a..48f1b2ac2cc 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: 20150411000035) do
+ActiveRecord::Schema.define(version: 20150411180045) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -132,6 +132,7 @@ ActiveRecord::Schema.define(version: 20150411000035) do
t.string "title"
t.string "type"
t.string "fingerprint"
+ t.boolean "public", default: false, null: false
end
add_index "keys", ["created_at", "id"], name: "index_keys_on_created_at_and_id", using: :btree
@@ -336,12 +337,12 @@ ActiveRecord::Schema.define(version: 20150411000035) do
t.string "import_url"
t.integer "visibility_level", default: 0, null: false
t.boolean "archived", default: false, null: false
+ t.string "avatar"
t.string "import_status"
t.float "repository_size", default: 0.0
t.integer "star_count", default: 0, null: false
t.string "import_type"
t.string "import_source"
- t.string "avatar"
end
add_index "projects", ["created_at", "id"], name: "index_projects_on_created_at_and_id", using: :btree
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 55d525fef66..971fe96fb8e 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -63,6 +63,7 @@ Parameters:
"snippets_enabled": false,
"created_at": "2013-09-30T13: 46: 02Z",
"last_activity_at": "2013-09-30T13: 46: 02Z",
+ "creator_id": 3,
"namespace": {
"created_at": "2013-09-30T13: 46: 02Z",
"description": "",
@@ -103,6 +104,7 @@ Parameters:
"snippets_enabled": false,
"created_at": "2013-09-30T13:46:02Z",
"last_activity_at": "2013-09-30T13:46:02Z",
+ "creator_id": 3,
"namespace": {
"created_at": "2013-09-30T13:46:02Z",
"description": "",
@@ -190,6 +192,7 @@ Parameters:
"snippets_enabled": false,
"created_at": "2013-09-30T13: 46: 02Z",
"last_activity_at": "2013-09-30T13: 46: 02Z",
+ "creator_id": 3,
"namespace": {
"created_at": "2013-09-30T13: 46: 02Z",
"description": "",
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 965d8fc313f..1d5fd4c8b0d 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -421,7 +421,7 @@ Quote break.
You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
-Note that inline HTML is disabled in the default Gitlab configuration, although it is [possible](https://github.com/gitlabhq/gitlabhq/pull/8007/commits) for the system administrator to enable it.
+See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows the `class`, `id`, and `style` attributes.
```no-highlight
<dl>
@@ -441,8 +441,6 @@ Note that inline HTML is disabled in the default Gitlab configuration, although
<dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
</dl>
-See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows the `class`, `id`, and `style` attributes.
-
## Horizontal Rule
```
diff --git a/features/admin/deploy_keys.feature b/features/admin/deploy_keys.feature
new file mode 100644
index 00000000000..9df47eb51fd
--- /dev/null
+++ b/features/admin/deploy_keys.feature
@@ -0,0 +1,21 @@
+@admin
+Feature: Admin Deploy Keys
+ Background:
+ Given I sign in as an admin
+ And there are public deploy keys in system
+
+ Scenario: Deploy Keys list
+ When I visit admin deploy keys page
+ Then I should see all public deploy keys
+
+ Scenario: Deploy Keys show
+ When I visit admin deploy keys page
+ And I click on first deploy key
+ Then I should see deploy key details
+
+ Scenario: Deploy Keys new
+ When I visit admin deploy keys page
+ And I click 'New Deploy Key'
+ And I submit new deploy key
+ Then I should be on admin deploy keys page
+ And I should see newly created deploy key
diff --git a/features/project/deploy_keys.feature b/features/project/deploy_keys.feature
index 13e3b9bbd2e..a71f6124d9c 100644
--- a/features/project/deploy_keys.feature
+++ b/features/project/deploy_keys.feature
@@ -6,7 +6,17 @@ Feature: Project Deploy Keys
Scenario: I should see deploy keys list
Given project has deploy key
When I visit project deploy keys page
- Then I should see project deploy keys
+ Then I should see project deploy key
+
+ Scenario: I should see project deploy keys
+ Given other project has deploy key
+ When I visit project deploy keys page
+ Then I should see other project deploy key
+
+ Scenario: I should see public deploy keys
+ Given public deploy key exists
+ When I visit project deploy keys page
+ Then I should see public deploy key
Scenario: I add new deploy key
Given I visit project deploy keys page
@@ -15,9 +25,16 @@ Feature: Project Deploy Keys
Then I should be on deploy keys page
And I should see newly created deploy key
- Scenario: I attach deploy key to project
+ Scenario: I attach other project deploy key to project
Given other project has deploy key
And I visit project deploy keys page
When I click attach deploy key
Then I should be on deploy keys page
And I should see newly created deploy key
+
+ Scenario: I attach public deploy key to project
+ Given public deploy key exists
+ And I visit project deploy keys page
+ When I click attach deploy key
+ Then I should be on deploy keys page
+ And I should see newly created deploy key
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index af01c7058ea..eb813884d1e 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -25,6 +25,12 @@ Feature: Project Issues
Given I click link "Release 0.4"
Then I should see issue "Release 0.4"
+ @javascript
+ Scenario: I visit issue page
+ Given I add a user to project "Shop"
+ And I click "author" dropdown
+ Then I see current user as the first user
+
Scenario: I submit new unassigned issue
Given I click link "New Issue"
And I submit new issue "500 error on profile"
diff --git a/features/steps/admin/deploy_keys.rb b/features/steps/admin/deploy_keys.rb
new file mode 100644
index 00000000000..fb0b611762e
--- /dev/null
+++ b/features/steps/admin/deploy_keys.rb
@@ -0,0 +1,57 @@
+class Spinach::Features::AdminDeployKeys < Spinach::FeatureSteps
+ include SharedAuthentication
+ include SharedPaths
+ include SharedAdmin
+
+ step 'there are public deploy keys in system' do
+ create(:deploy_key, public: true)
+ create(:another_deploy_key, public: true)
+ end
+
+ step 'I should see all public deploy keys' do
+ DeployKey.are_public.each do |p|
+ page.should have_content p.title
+ end
+ end
+
+ step 'I click on first deploy key' do
+ click_link DeployKey.are_public.first.title
+ end
+
+ step 'I should see deploy key details' do
+ deploy_key = DeployKey.are_public.first
+ current_path.should == admin_deploy_key_path(deploy_key)
+ page.should have_content(deploy_key.title)
+ page.should have_content(deploy_key.key)
+ end
+
+ step 'I visit admin deploy key page' do
+ visit admin_deploy_key_path(deploy_key)
+ end
+
+ step 'I visit admin deploy keys page' do
+ visit admin_deploy_keys_path
+ end
+
+ step 'I click \'New Deploy Key\'' do
+ click_link 'New Deploy Key'
+ end
+
+ step 'I submit new deploy key' do
+ fill_in "deploy_key_title", with: "laptop"
+ fill_in "deploy_key_key", with: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAzrEJUIR6Y03TCE9rIJ+GqTBvgb8t1jI9h5UBzCLuK4VawOmkLornPqLDrGbm6tcwM/wBrrLvVOqi2HwmkKEIecVO0a64A4rIYScVsXIniHRS6w5twyn1MD3sIbN+socBDcaldECQa2u1dI3tnNVcs8wi77fiRe7RSxePsJceGoheRQgC8AZ510UdIlO+9rjIHUdVN7LLyz512auAfYsgx1OfablkQ/XJcdEwDNgi9imI6nAXhmoKUm1IPLT2yKajTIC64AjLOnE0YyCh6+7RFMpiMyu1qiOCpdjYwTgBRiciNRZCH8xIedyCoAmiUgkUT40XYHwLuwiPJICpkAzp7Q== user@laptop"
+ click_button "Create"
+ end
+
+ step 'I should be on admin deploy keys page' do
+ current_path.should == admin_deploy_keys_path
+ end
+
+ step 'I should see newly created deploy key' do
+ page.should have_content(deploy_key.title)
+ end
+
+ def deploy_key
+ @deploy_key ||= DeployKey.are_public.first
+ end
+end
diff --git a/features/steps/project/deploy_keys.rb b/features/steps/project/deploy_keys.rb
index 4bf5cb5fa40..50e14513a7a 100644
--- a/features/steps/project/deploy_keys.rb
+++ b/features/steps/project/deploy_keys.rb
@@ -7,12 +7,24 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps
create(:deploy_keys_project, project: @project)
end
- step 'I should see project deploy keys' do
+ step 'I should see project deploy key' do
within '.enabled-keys' do
page.should have_content deploy_key.title
end
end
+ step 'I should see other project deploy key' do
+ within '.available-keys' do
+ page.should have_content other_deploy_key.title
+ end
+ end
+
+ step 'I should see public deploy key' do
+ within '.available-keys' do
+ page.should have_content public_deploy_key.title
+ end
+ end
+
step 'I click \'New Deploy Key\'' do
click_link 'New Deploy Key'
end
@@ -39,6 +51,10 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps
create(:deploy_keys_project, project: @second_project)
end
+ step 'public deploy key exists' do
+ create(:deploy_key, public: true)
+ end
+
step 'I click attach deploy key' do
within '.available-keys' do
click_link 'Enable'
@@ -50,4 +66,12 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps
def deploy_key
@project.deploy_keys.last
end
+
+ def other_deploy_key
+ @second_project.deploy_keys.last
+ end
+
+ def public_deploy_key
+ DeployKey.are_public.last
+ end
end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index e2834d51a27..b8e282b2029 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -59,6 +59,18 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
click_link "New Issue"
end
+ step 'I click "author" dropdown' do
+ first('.ajax-users-select').click
+ end
+
+ step 'I see current user as the first user' do
+ expect(page).to have_selector('.user-result', visible: true, count: 4)
+ users = page.all('.user-name')
+ users[0].text.should == 'Any'
+ users[1].text.should == 'Unassigned'
+ users[2].text.should == current_user.name
+ end
+
step 'I submit new issue "500 error on profile"' do
fill_in "issue_title", with: "500 error on profile"
click_button "Submit new issue"
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index 41f71ae29cb..b60ac5e3423 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -14,6 +14,13 @@ module SharedProject
@project.team << [@user, :master]
end
+ # Add another user to project "Shop"
+ step 'I add a user to project "Shop"' do
+ @project = Project.find_by(name: "Shop")
+ other_user = create(:user, name: 'Alpha')
+ @project.team << [other_user, :master]
+ end
+
# Create another specific project called "Forum"
step 'I own project "Forum"' do
@project = Project.find_by(name: "Forum")
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 51cb934616b..36332bc6514 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -54,6 +54,7 @@ module API
expose :name, :name_with_namespace
expose :path, :path_with_namespace
expose :issues_enabled, :merge_requests_enabled, :wiki_enabled, :snippets_enabled, :created_at, :last_activity_at
+ expose :creator_id
expose :namespace
expose :forked_from_project, using: Entities::ForkedFromProject, if: lambda{ | project, options | project.forked? }
expose :avatar_url
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index aabc7f1e69a..530f9d93de4 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -240,7 +240,7 @@ module Gitlab
gitlab_shell_version_file = "#{gitlab_shell_path}/VERSION"
if File.readable?(gitlab_shell_version_file)
- File.read(gitlab_shell_version_file)
+ File.read(gitlab_shell_version_file).chomp
end
end
diff --git a/lib/gitlab/closing_issue_extractor.rb b/lib/gitlab/closing_issue_extractor.rb
index a9fd59f03d9..ab184d95c05 100644
--- a/lib/gitlab/closing_issue_extractor.rb
+++ b/lib/gitlab/closing_issue_extractor.rb
@@ -1,21 +1,20 @@
module Gitlab
- module ClosingIssueExtractor
+ class ClosingIssueExtractor
ISSUE_CLOSING_REGEX = Regexp.new(Gitlab.config.gitlab.issue_closing_pattern)
- def self.closed_by_message_in_project(message, project)
- issues = []
+ def initialize(project, current_user = nil)
+ @extractor = Gitlab::ReferenceExtractor.new(project, current_user)
+ end
- unless message.nil?
- md = message.scan(ISSUE_CLOSING_REGEX)
+ def closed_by_message(message)
+ return [] if message.nil?
+
+ closing_statements = message.scan(ISSUE_CLOSING_REGEX).
+ map { |ref| ref[0] }.join(" ")
- md.each do |ref|
- extractor = Gitlab::ReferenceExtractor.new
- extractor.analyze(ref[0], project)
- issues += extractor.issues_for(project)
- end
- end
+ @extractor.analyze(closing_statements)
- issues.uniq
+ @extractor.issues
end
end
end
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index 75026aeaeb2..d054014039a 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -39,6 +39,7 @@ module Gitlab
end
def update_user_attributes
+ gl_user.skip_reconfirmation!
gl_user.email = auth_hash.email
# Build new identity only if we dont have have same one
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index f1e2ae74a3a..8073417a16a 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -192,6 +192,7 @@ module Gitlab
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
@@ -251,6 +252,7 @@ module Gitlab
elsif namespace = Namespace.find_by(path: identifier)
url =
if namespace.is_a?(Group)
+ return nil unless can?(current_user, :read_group, namespace)
group_url(identifier, only_path: options[:reference_only_path])
else
user_url(identifier, only_path: options[:reference_only_path])
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index c0419585c4b..a502a8fe9cd 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -1,94 +1,94 @@
module Gitlab
# Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor
- attr_accessor :users, :labels, :issues, :merge_requests, :snippets, :commits, :commit_ranges
+ attr_accessor :project, :current_user, :references
include ::Gitlab::Markdown
- def initialize
- @users, @labels, @issues, @merge_requests, @snippets, @commits, @commit_ranges =
- [], [], [], [], [], [], []
+ def initialize(project, current_user = nil)
+ @project = project
+ @current_user = current_user
end
- def analyze(string, project)
- text = string.dup
+ 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!(%r{<pre>.*?</pre>|<code>.*?</code>}m) { |match| '' }
text.gsub!(%r{^```.*?^```}m) { |match| '' }
- parse_references(text, project)
+ @references = Hash.new { |hash, type| hash[type] = [] }
+ parse_references(text)
end
# Given a valid project, resolve the extracted identifiers of the requested type to
# model objects.
- def users_for(project)
- users.map do |entry|
- project.users.where(username: entry[:id]).first
- end.reject(&:nil?)
+ 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
+ else
+ namespace.owner
+ end
+ end
+ end.flatten.compact.uniq
end
- def labels_for(project = nil)
- labels.map do |entry|
- project.labels.where(id: entry[:id]).first
- end.reject(&:nil?)
+ def labels
+ references[:label].uniq.map do |project, identifier|
+ project.labels.where(id: identifier).first
+ end.compact.uniq
end
- def issues_for(project = nil)
- issues.map do |entry|
- if should_lookup?(project, entry[:project])
- entry[:project].issues.where(iid: entry[:id]).first
+ def issues
+ references[:issue].uniq.map do |project, identifier|
+ if project.default_issues_tracker?
+ project.issues.where(iid: identifier).first
end
- end.reject(&:nil?)
+ end.compact.uniq
end
- def merge_requests_for(project = nil)
- merge_requests.map do |entry|
- if should_lookup?(project, entry[:project])
- entry[:project].merge_requests.where(iid: entry[:id]).first
- end
- end.reject(&:nil?)
+ def merge_requests
+ references[:merge_request].uniq.map do |project, identifier|
+ project.merge_requests.where(iid: identifier).first
+ end.compact.uniq
end
- def snippets_for(project)
- snippets.map do |entry|
- project.snippets.where(id: entry[:id]).first
- end.reject(&:nil?)
+ def snippets
+ references[:snippet].uniq.map do |project, identifier|
+ project.snippets.where(id: identifier).first
+ end.compact.uniq
end
- def commits_for(project = nil)
- commits.map do |entry|
- repo = entry[:project].repository if entry[:project]
- if should_lookup?(project, entry[:project])
- repo.commit(entry[:id]) if repo
- end
- end.reject(&:nil?)
+ def commits
+ references[:commit].uniq.map do |project, identifier|
+ repo = project.repository
+ repo.commit(identifier) if repo
+ end.compact.uniq
end
- def commit_ranges_for(project = nil)
- commit_ranges.map do |entry|
- repo = entry[:project].repository if entry[:project]
- if repo && should_lookup?(project, entry[:project])
- from_id, to_id = entry[:id].split(/\.{2,3}/, 2)
+ 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.reject(&:nil?)
+ end.compact.uniq
end
private
def reference_link(type, identifier, project, _)
- # Append identifier to the appropriate collection.
- send("#{type}s") << { project: project, id: identifier }
- end
-
- def should_lookup?(project, entry_project)
- if entry_project.nil?
- false
- else
- project.nil? || entry_project.default_issues_tracker?
- end
+ references[type] << [project, identifier]
end
end
end
diff --git a/spec/factories.rb b/spec/factories.rb
index fc103e5b133..b9bfd3cebb4 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -111,6 +111,9 @@ FactoryGirl.define do
key do
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmTillFzNTrrGgwaCKaSj+QCz81E6jBc/s9av0+3b1Hwfxgkqjl4nAK/OD2NjgyrONDTDfR8cRN4eAAy6nY8GLkOyYBDyuc5nTMqs5z3yVuTwf3koGm/YQQCmo91psZ2BgDFTor8SVEE5Mm1D1k3JDMhDFxzzrOtRYFPci9lskTJaBjpqWZ4E9rDTD2q/QZntCqbC3wE9uSemRQB5f8kik7vD/AD8VQXuzKladrZKkzkONCPWsXDspUitjM8HkQdOf0PsYn1CMUC1xKYbCxkg5TkEosIwGv6CoEArUrdu/4+10LVslq494mAvEItywzrluCLCnwELfW+h/m8UHoVhZ"
end
+
+ factory :another_deploy_key, class: 'DeployKey' do
+ end
end
factory :invalid_key do
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index 21a3a4bf937..4cfaab03caf 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -1,14 +1,37 @@
require 'spec_helper'
-describe 'Users', feature: true do
- describe "GET /users/sign_in" do
- it "should create a new user account" do
- visit new_user_session_path
- fill_in "user_name", with: "Name Surname"
- fill_in "user_username", with: "Great"
- fill_in "user_email", with: "name@mail.com"
- fill_in "user_password_sign_up", with: "password1234"
- expect { click_button "Sign up" }.to change { User.count }.by(1)
- end
+feature 'Users' do
+ around do |ex|
+ old_url_options = Rails.application.routes.default_url_options
+ Rails.application.routes.default_url_options = { host: 'example.foo' }
+ ex.run
+ Rails.application.routes.default_url_options = old_url_options
+ end
+
+ scenario 'GET /users/sign_in creates a new user account' do
+ visit new_user_session_path
+ fill_in 'user_name', with: 'Name Surname'
+ fill_in 'user_username', with: 'Great'
+ fill_in 'user_email', with: 'name@mail.com'
+ fill_in 'user_password_sign_up', with: 'password1234'
+ expect { click_button 'Sign up' }.to change { User.count }.by(1)
+ end
+
+ scenario 'Successful user signin invalidates password reset token' do
+ user = create(:user)
+ expect(user.reset_password_token).to be_nil
+
+ visit new_user_password_path
+ fill_in 'user_email', with: user.email
+ click_button 'Reset password'
+
+ user.reload
+ expect(user.reset_password_token).not_to be_nil
+
+ login_with(user)
+ expect(current_path).to eq root_path
+
+ user.reload
+ expect(user.reset_password_token).to be_nil
end
end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 0d06c6ffb82..944e743675c 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -4,6 +4,11 @@ describe GitlabMarkdownHelper do
include ApplicationHelper
include IssuesHelper
+ # TODO: Properly test this
+ def can?(*)
+ true
+ end
+
let!(:project) { create(:project) }
let(:empty_project) { create(:empty_project) }
@@ -15,6 +20,9 @@ describe GitlabMarkdownHelper do
let(:snippet) { create(:project_snippet, project: project) }
let(:member) { project.project_members.where(user_id: user).first }
+ # Helper expects a current_user method.
+ let(:current_user) { user }
+
def url_helper(image_name)
File.join(root_url, 'assets', image_name)
end
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index aef1108e333..e99c3f5bc11 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe SubmoduleHelper do
+ include RepoHelpers
+
describe 'submodule links' do
let(:submodule_item) { double(id: 'hash', path: 'rack') }
let(:config) { Gitlab.config.gitlab }
@@ -111,6 +113,39 @@ describe SubmoduleHelper do
expect(submodule_links(submodule_item)).to eq([ repo.submodule_url_for, nil ])
end
end
+
+ context 'submodules with relative links' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, group: group) }
+
+ 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
+ end
end
def stub_url(url)
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index c96ee78e5fd..cb7b0fbb890 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -5,126 +5,128 @@ describe Gitlab::ClosingIssueExtractor do
let(:issue) { create(:issue, project: project) }
let(:iid1) { issue.iid }
- describe :closed_by_message_in_project do
+ subject { described_class.new(project, project.creator) }
+
+ describe "#closed_by_message" do
context 'with a single reference' do
it do
message = "Awesome commit (Closes ##{iid1})"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Awesome commit (closes ##{iid1})"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Closed ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "closed ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Closing ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "closing ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Close ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "close ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Awesome commit (Fixes ##{iid1})"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Awesome commit (fixes ##{iid1})"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Fixed ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "fixed ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Fixing ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "fixing ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Fix ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "fix ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Awesome commit (Resolves ##{iid1})"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Awesome commit (resolves ##{iid1})"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Resolved ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "resolved ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Resolving ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "resolving ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "Resolve ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
it do
message = "resolve ##{iid1}"
- expect(subject.closed_by_message_in_project(message, project)).to eq([issue])
+ expect(subject.closed_by_message(message)).to eq([issue])
end
end
@@ -137,28 +139,28 @@ describe Gitlab::ClosingIssueExtractor do
it 'fetches issues in single line message' do
message = "Closes ##{iid1} and fix ##{iid2}"
- expect(subject.closed_by_message_in_project(message, project)).
+ expect(subject.closed_by_message(message)).
to eq([issue, other_issue])
end
it 'fetches comma-separated issues references in single line message' do
message = "Closes ##{iid1}, closes ##{iid2}"
- expect(subject.closed_by_message_in_project(message, project)).
+ expect(subject.closed_by_message(message)).
to eq([issue, other_issue])
end
it 'fetches comma-separated issues numbers in single line message' do
message = "Closes ##{iid1}, ##{iid2} and ##{iid3}"
- expect(subject.closed_by_message_in_project(message, project)).
+ expect(subject.closed_by_message(message)).
to eq([issue, other_issue, third_issue])
end
it 'fetches issues in multi-line message' do
message = "Awesome commit (closes ##{iid1})\nAlso fixes ##{iid2}"
- expect(subject.closed_by_message_in_project(message, project)).
+ expect(subject.closed_by_message(message)).
to eq([issue, other_issue])
end
@@ -166,7 +168,7 @@ describe Gitlab::ClosingIssueExtractor do
message = "Awesome commit (closes ##{iid1})\n"\
"Also fixing issues ##{iid2}, ##{iid3} and #4"
- expect(subject.closed_by_message_in_project(message, project)).
+ expect(subject.closed_by_message(message)).
to eq([issue, other_issue, third_issue])
end
end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index b3f4bb5aeda..c9fb62b61ae 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -1,73 +1,76 @@
require 'spec_helper'
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', nil)
- expect(subject.users).to eq([{ project: nil, id: 'user' }])
+ 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', nil)
- expect(subject.issues).to eq([{ project: nil, id: '1234' }])
+ 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', nil)
- expect(subject.issues).to eq([{ project: nil, id: 'JIRA-1234' }])
+ 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", nil)
- expect(subject.merge_requests).to eq([{ project: nil, id: '43' }])
+ 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', nil)
- expect(subject.snippets).to eq([{ project: nil, id: '12' }])
+ 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', nil)
- expect(subject.commits).to eq([{ project: nil, id: '98cf0ae3' }])
+ 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', nil)
- expect(subject.commit_ranges).to eq([{ project: nil, id: '98cf0ae3...98cf0ae4' }])
+ 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', nil)
- expect(subject.users).to eq([
- { project: nil, id: 'me' },
- { project: nil, id: 'you' }
+ 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, nil)
+ 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>```", nil)
+ 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>```", nil)
+ 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```", nil)
+ 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```', nil)
- expect(subject.issues).to eq([{ project: nil, id: '1234' }])
+ 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
@@ -75,83 +78,79 @@ describe Gitlab::ReferenceExtractor do
expect(subject).to respond_to(*accessors)
end
- context 'with a project' do
- let(:project) { create(:project) }
-
- it 'accesses valid user objects on the project team' do
- @u_foo = create(:user, username: 'foo')
- @u_bar = create(:user, username: 'bar')
- create(:user, username: 'offteam')
+ it 'accesses valid user objects' do
+ @u_foo = create(:user, username: 'foo')
+ @u_bar = create(:user, username: 'bar')
+ @u_offteam = create(:user, username: 'offteam')
- project.team << [@u_foo, :reporter]
- project.team << [@u_bar, :guest]
+ project.team << [@u_foo, :reporter]
+ project.team << [@u_bar, :guest]
- subject.analyze('@foo, @baduser, @bar, and @offteam', project)
- expect(subject.users_for(project)).to eq([@u_foo, @u_bar])
- end
+ subject.analyze('@foo, @baduser, @bar, and @offteam')
+ expect(subject.users).to eq([@u_foo, @u_bar, @u_offteam])
+ end
- it 'accesses valid issue objects' do
- @i0 = create(:issue, project: project)
- @i1 = create(:issue, project: project)
+ it 'accesses valid issue objects' do
+ @i0 = create(:issue, project: project)
+ @i1 = create(:issue, project: project)
- subject.analyze("##{@i0.iid}, ##{@i1.iid}, and #999.", project)
- expect(subject.issues_for(project)).to eq([@i0, @i1])
- end
+ subject.analyze("##{@i0.iid}, ##{@i1.iid}, and #999.")
+ expect(subject.issues).to eq([@i0, @i1])
+ end
- it 'accesses valid merge requests' do
- @m0 = create(:merge_request, source_project: project, target_project: project, source_branch: 'aaa')
- @m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'bbb')
+ it 'accesses valid merge requests' do
+ @m0 = create(:merge_request, source_project: project, target_project: project, source_branch: 'aaa')
+ @m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'bbb')
- subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.", project)
- expect(subject.merge_requests_for(project)).to eq([@m1, @m0])
- end
+ subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.")
+ expect(subject.merge_requests).to eq([@m1, @m0])
+ end
- it 'accesses valid snippets' do
- @s0 = create(:project_snippet, project: project)
- @s1 = create(:project_snippet, project: project)
- @s2 = create(:project_snippet)
+ it 'accesses valid snippets' do
+ @s0 = create(:project_snippet, project: project)
+ @s1 = create(:project_snippet, project: project)
+ @s2 = create(:project_snippet)
- subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}", project)
- expect(subject.snippets_for(project)).to eq([@s0, @s1])
- end
+ subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}")
+ expect(subject.snippets).to eq([@s0, @s1])
+ end
- it 'accesses valid commits' do
- commit = project.repository.commit('master')
+ it 'accesses valid commits' do
+ commit = project.repository.commit('master')
- subject.analyze("this references commits #{commit.sha[0..6]} and 012345",
- project)
- extracted = subject.commits_for(project)
- expect(extracted.size).to eq(1)
- expect(extracted[0].sha).to eq(commit.sha)
- expect(extracted[0].message).to eq(commit.message)
- end
+ subject.analyze("this references commits #{commit.sha[0..6]} and 012345")
+ extracted = subject.commits
+ expect(extracted.size).to eq(1)
+ expect(extracted[0].sha).to eq(commit.sha)
+ expect(extracted[0].message).to eq(commit.message)
+ end
- it 'accesses valid commit ranges' do
- commit = project.repository.commit('master')
- earlier_commit = project.repository.commit('master~2')
+ it 'accesses valid commit ranges' do
+ commit = project.repository.commit('master')
+ earlier_commit = project.repository.commit('master~2')
- subject.analyze("this references commits #{earlier_commit.sha[0..6]}...#{commit.sha[0..6]}",
- project)
- extracted = subject.commit_ranges_for(project)
- 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)
- end
+ 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)
end
context 'with a project with an underscore' do
- let(:project) { create(:project, path: 'test_project') }
- let(:issue) { create(:issue, project: project) }
+ let(:other_project) { create(:project, path: 'test_project') }
+ let(:issue) { create(:issue, project: other_project) }
+
+ before do
+ other_project.team << [project.creator, :developer]
+ end
it 'handles project issue references' do
- subject.analyze("this refers issue #{project.path_with_namespace}##{issue.iid}",
- project)
- extracted = subject.issues_for(project)
+ subject.analyze("this refers issue #{other_project.path_with_namespace}##{issue.iid}")
+ extracted = subject.issues
expect(extracted.size).to eq(1)
expect(extracted).to eq([issue])
end
-
end
end
diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb
index f351aab9238..7032b777144 100644
--- a/spec/models/deploy_keys_project_spec.rb
+++ b/spec/models/deploy_keys_project_spec.rb
@@ -28,17 +28,32 @@ describe DeployKeysProject do
let(:deploy_key) { subject.deploy_key }
context "when the deploy key is only used by this project" do
- it "destroys the deploy key" do
- subject.destroy
+ context "when the deploy key is public" do
+ before do
+ deploy_key.update_attribute(:public, true)
+ end
- expect {
- deploy_key.reload
- }.to raise_error(ActiveRecord::RecordNotFound)
+ it "doesn't destroy the deploy key" do
+ subject.destroy
+
+ expect {
+ deploy_key.reload
+ }.not_to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+
+ context "when the deploy key is private" do
+ it "destroys the deploy key" do
+ subject.destroy
+
+ expect {
+ deploy_key.reload
+ }.to raise_error(ActiveRecord::RecordNotFound)
+ end
end
end
context "when the deploy key is used by more than one project" do
-
let!(:other_project) { create(:project) }
before do
diff --git a/spec/models/project_services/buildbox_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb
index 9f29fbe12b0..e987241f3ca 100644
--- a/spec/models/project_services/buildbox_service_spec.rb
+++ b/spec/models/project_services/buildkite_service_spec.rb
@@ -19,7 +19,7 @@
require 'spec_helper'
-describe BuildboxService do
+describe BuildkiteService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
@@ -32,7 +32,7 @@ describe BuildboxService do
default_branch: 'default-brancho'
)
- @service = BuildboxService.new
+ @service = BuildkiteService.new
@service.stub(
project: @project,
service_hook: true,
diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb
index 610f33c5823..6a557d839ca 100644
--- a/spec/models/project_services/gitlab_ci_service_spec.rb
+++ b/spec/models/project_services/gitlab_ci_service_spec.rb
@@ -46,4 +46,25 @@ describe GitlabCiService do
it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://ci.gitlab.org/projects/2/refs/master/commits/2ab7834c")}
end
end
+
+ describe "Fork registration" do
+ before do
+ @old_project = create(:empty_project)
+ @project = create(:empty_project)
+ @user = create(:user)
+
+ @service = GitlabCiService.new
+ @service.stub(
+ service_hook: true,
+ project_url: 'http://ci.gitlab.org/projects/2',
+ token: 'verySecret',
+ project: @old_project
+ )
+ end
+
+ it "performs http reuquest to ci" do
+ stub_request(:post, "http://ci.gitlab.org/api/v1/forks")
+ @service.fork_registration(@project, @user.private_token)
+ end
+ end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index d9bd91f5990..042352311da 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -168,12 +168,11 @@ end
# project_deploy_keys GET /:project_id/deploy_keys(.:format) deploy_keys#index
# POST /:project_id/deploy_keys(.:format) deploy_keys#create
# new_project_deploy_key GET /:project_id/deploy_keys/new(.:format) deploy_keys#new
-# edit_project_deploy_key GET /:project_id/deploy_keys/:id/edit(.:format) deploy_keys#edit
# project_deploy_key GET /:project_id/deploy_keys/:id(.:format) deploy_keys#show
-# PUT /:project_id/deploy_keys/:id(.:format) deploy_keys#update
# DELETE /:project_id/deploy_keys/:id(.:format) deploy_keys#destroy
describe Projects::DeployKeysController, 'routing' do
it_behaves_like 'RESTful project resources' do
+ let(:actions) { [:index, :show, :new, :create] }
let(:controller) { 'deploy_keys' }
end
end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index e55a2e3f8a0..c9025bdf133 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -40,6 +40,17 @@ describe Projects::ForkService do
expect(@to_project.errors[:base]).not_to include("Fork transaction failed.")
end
end
+
+ context 'GitLab CI is enabled' do
+ it "calls fork registrator for CI" do
+ @from_project.build_missing_services
+ @from_project.gitlab_ci_service.update_attributes(active: true)
+
+ expect(ForkRegistrationWorker).to receive(:perform_async)
+
+ fork_project(@from_project, @to_user)
+ end
+ end
end
describe :fork_to_namespace do
@@ -89,7 +100,8 @@ describe Projects::ForkService do
def fork_project(from_project, user, fork_success = true, params = {})
context = Projects::ForkService.new(from_project, user, params)
- shell = double('gitlab_shell').stub(fork_repository: fork_success)
+ shell = double('gitlab_shell')
+ shell.stub(fork_repository: fork_success)
context.stub(gitlab_shell: shell)
context.execute
end
diff --git a/spec/workers/fork_registration_worker_spec.rb b/spec/workers/fork_registration_worker_spec.rb
new file mode 100644
index 00000000000..cc6f574b29c
--- /dev/null
+++ b/spec/workers/fork_registration_worker_spec.rb
@@ -0,0 +1,10 @@
+
+require 'spec_helper'
+
+describe ForkRegistrationWorker do
+ context "as a resque worker" do
+ it "reponds to #perform" do
+ expect(ForkRegistrationWorker.new).to respond_to(:perform)
+ end
+ end
+end