Commit 8aa025bb authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'master' of https://dev.gitlab.org/gitlab/gitlabhq

Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parents 89af76ed a2482210
...@@ -100,6 +100,10 @@ v 8.11.4 ...@@ -100,6 +100,10 @@ v 8.11.4
- Creating an issue through our API now emails label subscribers !5720 - Creating an issue through our API now emails label subscribers !5720
- Block concurrent updates for Pipeline - Block concurrent updates for Pipeline
- Don't create groups for unallowed users when importing projects - Don't create groups for unallowed users when importing projects
- Fix resolving conflicts on forks
- Fix diff commenting on merge requests created prior to 8.10
- Don't create groups for unallowed users when importing projects
- Scope webhooks/services that will run for confidential issues
- Fix issue boards leak private label names and descriptions - Fix issue boards leak private label names and descriptions
- Fix broken gitlab:backup:restore because of bad permissions on repo storage !6098 (Dirk Hörner) - Fix broken gitlab:backup:restore because of bad permissions on repo storage !6098 (Dirk Hörner)
- Remove gitorious. !5866 - Remove gitorious. !5866
......
...@@ -10,21 +10,24 @@ ...@@ -10,21 +10,24 @@
ImporterStatus.prototype.initStatusPage = function() { ImporterStatus.prototype.initStatusPage = function() {
$('.js-add-to-import').off('click').on('click', (function(_this) { $('.js-add-to-import').off('click').on('click', (function(_this) {
return function(e) { return function(e) {
var $btn, $namespace_input, $target_field, $tr, id, new_namespace; var $btn, $namespace_input, $target_field, $tr, id, target_namespace;
$btn = $(e.currentTarget); $btn = $(e.currentTarget);
$tr = $btn.closest('tr'); $tr = $btn.closest('tr');
$target_field = $tr.find('.import-target'); $target_field = $tr.find('.import-target');
$namespace_input = $target_field.find('input'); $namespace_input = $target_field.find('input');
id = $tr.attr('id').replace('repo_', ''); id = $tr.attr('id').replace('repo_', '');
new_namespace = null; target_namespace = null;
if ($namespace_input.length > 0) { if ($namespace_input.length > 0) {
new_namespace = $namespace_input.prop('value'); target_namespace = $namespace_input.prop('value');
$target_field.empty().append(new_namespace + "/" + ($target_field.data('project_name'))); $target_field.empty().append(target_namespace + "/" + ($target_field.data('project_name')));
} }
$btn.disable().addClass('is-loading'); $btn.disable().addClass('is-loading');
return $.post(_this.import_url, { return $.post(_this.import_url, {
repo_id: id, repo_id: id,
new_namespace: new_namespace target_namespace: target_namespace
}, { }, {
dataType: 'script' dataType: 'script'
}); });
......
...@@ -13,7 +13,7 @@ module ServiceParams ...@@ -13,7 +13,7 @@ module ServiceParams
# `issue_events` and `merge_request_events` (singular!) # `issue_events` and `merge_request_events` (singular!)
# See app/helpers/services_helper.rb for how we # See app/helpers/services_helper.rb for how we
# make those event names plural as special case. # make those event names plural as special case.
:issues_events, :merge_requests_events, :issues_events, :confidential_issues_events, :merge_requests_events,
:notify_only_broken_builds, :notify_only_broken_pipelines, :notify_only_broken_builds, :notify_only_broken_pipelines,
:add_pusher, :send_from_committer_email, :disable_diffs, :add_pusher, :send_from_committer_email, :disable_diffs,
:external_wiki_url, :notify, :color, :external_wiki_url, :notify, :color,
......
class Import::BaseController < ApplicationController class Import::BaseController < ApplicationController
private private
def get_or_create_namespace def find_or_create_namespace(name, owner)
return current_user.namespace if name == owner
return current_user.namespace unless current_user.can_create_group?
begin begin
namespace = Group.create!(name: @target_namespace, path: @target_namespace, owner: current_user) name = params[:target_namespace].presence || name
namespace = Group.create!(name: name, path: name, owner: current_user)
namespace.add_owner(current_user) namespace.add_owner(current_user)
namespace
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
namespace = Namespace.find_by_path_or_name(@target_namespace) Namespace.find_by_path_or_name(name)
unless current_user.can?(:create_projects, namespace)
@already_been_taken = true
return false
end
end end
namespace
end end
end end
...@@ -35,23 +35,20 @@ class Import::BitbucketController < Import::BaseController ...@@ -35,23 +35,20 @@ class Import::BitbucketController < Import::BaseController
end end
def create def create
@repo_id = params[:repo_id] || "" @repo_id = params[:repo_id].to_s
repo = client.project(@repo_id.gsub("___", "/")) repo = client.project(@repo_id.gsub('___', '/'))
@project_name = repo["slug"] @project_name = repo['slug']
@target_namespace = find_or_create_namespace(repo['owner'], client.user['user']['username'])
repo_owner = repo["owner"]
repo_owner = current_user.username if repo_owner == client.user["user"]["username"]
@target_namespace = params[:new_namespace].presence || repo_owner
namespace = get_or_create_namespace || (render and return)
unless Gitlab::BitbucketImport::KeyAdder.new(repo, current_user, access_params).execute unless Gitlab::BitbucketImport::KeyAdder.new(repo, current_user, access_params).execute
@access_denied = true render 'deploy_key' and return
render
return
end end
@project = Gitlab::BitbucketImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute if current_user.can?(:create_projects, @target_namespace)
@project = Gitlab::BitbucketImport::ProjectCreator.new(repo, @target_namespace, current_user, access_params).execute
else
render 'unauthorized'
end
end end
private private
......
...@@ -41,14 +41,13 @@ class Import::GithubController < Import::BaseController ...@@ -41,14 +41,13 @@ class Import::GithubController < Import::BaseController
@repo_id = params[:repo_id].to_i @repo_id = params[:repo_id].to_i
repo = client.repo(@repo_id) repo = client.repo(@repo_id)
@project_name = repo.name @project_name = repo.name
@target_namespace = find_or_create_namespace(repo.owner.login, client.user.login)
repo_owner = repo.owner.login if current_user.can?(:create_projects, @target_namespace)
repo_owner = current_user.username if repo_owner == client.user.login @project = Gitlab::GithubImport::ProjectCreator.new(repo, @target_namespace, current_user, access_params).execute
@target_namespace = params[:new_namespace].presence || repo_owner else
render 'unauthorized'
namespace = get_or_create_namespace || (render and return) end
@project = Gitlab::GithubImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
end end
private private
......
...@@ -26,15 +26,14 @@ class Import::GitlabController < Import::BaseController ...@@ -26,15 +26,14 @@ class Import::GitlabController < Import::BaseController
def create def create
@repo_id = params[:repo_id].to_i @repo_id = params[:repo_id].to_i
repo = client.project(@repo_id) repo = client.project(@repo_id)
@project_name = repo["name"] @project_name = repo['name']
@target_namespace = find_or_create_namespace(repo['namespace']['path'], client.user['username'])
repo_owner = repo["namespace"]["path"] if current_user.can?(:create_projects, @target_namespace)
repo_owner = current_user.username if repo_owner == client.user["username"] @project = Gitlab::GitlabImport::ProjectCreator.new(repo, @target_namespace, current_user, access_params).execute
@target_namespace = params[:new_namespace].presence || repo_owner else
render 'unauthorized'
namespace = get_or_create_namespace || (render and return) end
@project = Gitlab::GitlabImport::ProjectCreator.new(repo, namespace, current_user, access_params).execute
end end
private private
......
...@@ -59,6 +59,7 @@ class Projects::HooksController < Projects::ApplicationController ...@@ -59,6 +59,7 @@ class Projects::HooksController < Projects::ApplicationController
:pipeline_events, :pipeline_events,
:enable_ssl_verification, :enable_ssl_verification,
:issues_events, :issues_events,
:confidential_issues_events,
:merge_requests_events, :merge_requests_events,
:note_events, :note_events,
:push_events, :push_events,
......
module ImportHelper module ImportHelper
def import_project_target(owner, name)
namespace = current_user.can_create_group? ? owner : current_user.namespace_path
"#{namespace}/#{name}"
end
def github_project_link(path_with_namespace) def github_project_link(path_with_namespace)
link_to path_with_namespace, github_project_url(path_with_namespace), target: '_blank' link_to path_with_namespace, github_project_url(path_with_namespace), target: '_blank'
end end
......
...@@ -8,7 +8,9 @@ module ServicesHelper ...@@ -8,7 +8,9 @@ module ServicesHelper
when "note" when "note"
"Event will be triggered when someone adds a comment" "Event will be triggered when someone adds a comment"
when "issue" when "issue"
"Event will be triggered when an issue is created/updated/merged" "Event will be triggered when an issue is created/updated/closed"
when "confidential_issue"
"Event will be triggered when a confidential issue is created/updated/closed"
when "merge_request" when "merge_request"
"Event will be triggered when a merge request is created/updated/merged" "Event will be triggered when a merge request is created/updated/merged"
when "build" when "build"
...@@ -19,7 +21,7 @@ module ServicesHelper ...@@ -19,7 +21,7 @@ module ServicesHelper
end end
def service_event_field_name(event) def service_event_field_name(event)
event = event.pluralize if %w[merge_request issue].include?(event) event = event.pluralize if %w[merge_request issue confidential_issue].include?(event)
"#{event}_events" "#{event}_events"
end end
end end
...@@ -2,6 +2,7 @@ class ProjectHook < WebHook ...@@ -2,6 +2,7 @@ class ProjectHook < WebHook
belongs_to :project belongs_to :project
scope :issue_hooks, -> { where(issues_events: true) } scope :issue_hooks, -> { where(issues_events: true) }
scope :confidential_issue_hooks, -> { where(confidential_issues_events: true) }
scope :note_hooks, -> { where(note_events: true) } scope :note_hooks, -> { where(note_events: true) }
scope :merge_request_hooks, -> { where(merge_requests_events: true) } scope :merge_request_hooks, -> { where(merge_requests_events: true) }
scope :build_hooks, -> { where(build_events: true) } scope :build_hooks, -> { where(build_events: true) }
......
...@@ -4,6 +4,7 @@ class WebHook < ActiveRecord::Base ...@@ -4,6 +4,7 @@ class WebHook < ActiveRecord::Base
default_value_for :push_events, true default_value_for :push_events, true
default_value_for :issues_events, false default_value_for :issues_events, false
default_value_for :confidential_issues_events, false
default_value_for :note_events, false default_value_for :note_events, false
default_value_for :merge_requests_events, false default_value_for :merge_requests_events, false
default_value_for :tag_push_events, false default_value_for :tag_push_events, false
......
...@@ -39,7 +39,7 @@ class HipchatService < Service ...@@ -39,7 +39,7 @@ class HipchatService < Service
end end
def supported_events def supported_events
%w(push issue merge_request note tag_push build) %w(push issue confidential_issue merge_request note tag_push build)
end end
def execute(data) def execute(data)
......
...@@ -44,7 +44,7 @@ class SlackService < Service ...@@ -44,7 +44,7 @@ class SlackService < Service
end end
def supported_events def supported_events
%w(push issue merge_request note tag_push build wiki_page) %w(push issue confidential_issue merge_request note tag_push build wiki_page)
end end
def execute(data) def execute(data)
......
...@@ -7,6 +7,7 @@ class Service < ActiveRecord::Base ...@@ -7,6 +7,7 @@ class Service < ActiveRecord::Base
default_value_for :active, false default_value_for :active, false
default_value_for :push_events, true default_value_for :push_events, true
default_value_for :issues_events, true default_value_for :issues_events, true
default_value_for :confidential_issues_events, true
default_value_for :merge_requests_events, true default_value_for :merge_requests_events, true
default_value_for :tag_push_events, true default_value_for :tag_push_events, true
default_value_for :note_events, true default_value_for :note_events, true
...@@ -33,6 +34,7 @@ class Service < ActiveRecord::Base ...@@ -33,6 +34,7 @@ class Service < ActiveRecord::Base
scope :push_hooks, -> { where(push_events: true, active: true) } scope :push_hooks, -> { where(push_events: true, active: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) } scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
scope :issue_hooks, -> { where(issues_events: true, active: true) } scope :issue_hooks, -> { where(issues_events: true, active: true) }
scope :confidential_issue_hooks, -> { where(confidential_issues_events: true, active: true) }
scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) } scope :merge_request_hooks, -> { where(merge_requests_events: true, active: true) }
scope :note_hooks, -> { where(note_events: true, active: true) } scope :note_hooks, -> { where(note_events: true, active: true) }
scope :build_hooks, -> { where(build_events: true, active: true) } scope :build_hooks, -> { where(build_events: true, active: true) }
...@@ -100,7 +102,7 @@ class Service < ActiveRecord::Base ...@@ -100,7 +102,7 @@ class Service < ActiveRecord::Base
end end
def supported_events def supported_events
%w(push tag_push issue merge_request wiki_page) %w(push tag_push issue confidential_issue merge_request wiki_page)
end end
def execute(data) def execute(data)
......
...@@ -15,8 +15,9 @@ module Issues ...@@ -15,8 +15,9 @@ module Issues
def execute_hooks(issue, action = 'open') def execute_hooks(issue, action = 'open')
issue_data = hook_data(issue, action) issue_data = hook_data(issue, action)
issue.project.execute_hooks(issue_data, :issue_hooks) hooks_scope = issue.confidential? ? :confidential_issue_hooks : :issue_hooks
issue.project.execute_services(issue_data, :issue_hooks) issue.project.execute_hooks(issue_data, hooks_scope)
issue.project.execute_services(issue_data, hooks_scope)
end end
end end
end end
- if @already_been_taken - if @project.persisted?
:plain
tr = $("tr#repo_#{@repo_id}")
target_field = tr.find(".import-target")
import_button = tr.find(".btn-import")
origin_target = target_field.text()
project_name = "#{@project_name}"
origin_namespace = "#{@target_namespace}"
target_field.empty()
target_field.append("<p class='alert alert-danger'>This namespace already been taken! Please choose another one</p>")
target_field.append("<input type='text' name='target_namespace' />")
target_field.append("/" + project_name)
target_field.data("project_name", project_name)
target_field.find('input').prop("value", origin_namespace)
import_button.enable().removeClass('is-loading')
- elsif @access_denied
:plain
job = $("tr#repo_#{@repo_id}")
job.find(".import-actions").html("<p class='alert alert-danger'>Access denied! Please verify you can add deploy keys to this repository.</p>")
- elsif @project.persisted?
:plain :plain
job = $("tr#repo_#{@repo_id}") job = $("tr#repo_#{@repo_id}")
job.attr("id", "project_#{@project.id}") job.attr("id", "project_#{@project.id}")
......
:plain
tr = $("tr#repo_#{@repo_id}")
target_field = tr.find(".import-target")
import_button = tr.find(".btn-import")
origin_target = target_field.text()
project_name = "#{@project_name}"
origin_namespace = "#{@target_namespace.path}"
target_field.empty()
target_field.append("<p class='alert alert-danger'>This namespace has already been taken! Please choose another one.</p>")
target_field.append("<input type='text' name='target_namespace' />")
target_field.append("/" + project_name)
target_field.data("project_name", project_name)
target_field.find('input').prop("value", origin_namespace)
import_button.enable().removeClass('is-loading')
:plain
job = $("tr#repo_#{@repo_id}")
job.find(".import-actions").html("<p class='alert alert-danger'>Access denied! Please verify you can add deploy keys to this repository.</p>")
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
%td %td
= link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank" = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
%td.import-target %td.import-target
= "#{repo["owner"]}/#{repo["slug"]}" = import_project_target(repo['owner'], repo['slug'])
%td.import-actions.job-status %td.import-actions.job-status
= button_tag class: "btn btn-import js-add-to-import" do = button_tag class: "btn btn-import js-add-to-import" do
Import Import
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
%td %td
= github_project_link(repo.full_name) = github_project_link(repo.full_name)
%td.import-target %td.import-target
= repo.full_name = import_project_target(repo.owner.login, repo.name)
%td.import-actions.job-status %td.import-actions.job-status
= button_tag class: "btn btn-import js-add-to-import" do = button_tag class: "btn btn-import js-add-to-import" do
Import Import
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
%td %td
= link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank" = link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank"
%td.import-target %td.import-target
= repo["path_with_namespace"] = import_project_target(repo['namespace']['path'], repo['name'])
%td.import-actions.job-status %td.import-actions.job-status
= button_tag class: "btn btn-import js-add-to-import" do = button_tag class: "btn btn-import js-add-to-import" do
Import Import
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
.col-md-8.col-lg-7 .col-md-8.col-lg-7
%strong.light-header= hook.url %strong.light-header= hook.url
%div %div
- %w(push_events tag_push_events issues_events note_events merge_requests_events build_events pipeline_events wiki_page_events).each do |trigger| - %w(push_events tag_push_events issues_events confidential_issues_events note_events merge_requests_events build_events pipeline_events wiki_page_events).each do |trigger|
- if hook.send(trigger) - if hook.send(trigger)
%span.label.label-gray.deploy-project-label= trigger.titleize %span.label.label-gray.deploy-project-label= trigger.titleize
.col-md-4.col-lg-5.text-right-lg.prepend-top-5 .col-md-4.col-lg-5.text-right-lg.prepend-top-5
......
...@@ -51,6 +51,13 @@ ...@@ -51,6 +51,13 @@
%strong Issues events %strong Issues events
%p.light %p.light
This URL will be triggered when an issue is created/updated/merged This URL will be triggered when an issue is created/updated/merged
%li
= f.check_box :confidential_issues_events, class: 'pull-left'
.prepend-left-20
= f.label :confidential_issues_events, class: 'list-label' do
%strong Confidential Issues events
%p.light
This URL will be triggered when a confidential issue is created/updated/merged
%li %li
= f.check_box :merge_requests_events, class: 'pull-left' = f.check_box :merge_requests_events, class: 'pull-left'
.prepend-left-20 .prepend-left-20
......
class AddConfidentialIssuesEventsToWebHooks < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default :web_hooks, :confidential_issues_events, :boolean, default: false, allow_null: false
end
def down
remove_column :web_hooks, :confidential_issues_events
end
end
class AddConfidentialIssuesEventsToServices < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_column_with_default :services, :confidential_issues_events, :boolean, default: true, allow_null: false
end
def down
remove_column :services, :confidential_issues_events
end
end
class SetConfidentialIssuesEventsOnWebhooks < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
update_column_in_batches(:web_hooks, :confidential_issues_events, true) do |table, query|
query.where(table[:issues_events].eq(true))
end
end
def down
# noop
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160831223750) do ActiveRecord::Schema.define(version: 20160901141443) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -922,6 +922,7 @@ ActiveRecord::Schema.define(version: 20160831223750) do ...@@ -922,6 +922,7 @@ ActiveRecord::Schema.define(version: 20160831223750) do
t.boolean "default", default: false t.boolean "default", default: false
t.boolean "wiki_page_events", default: true t.boolean "wiki_page_events", default: true
t.boolean "pipeline_events", default: false, null: false t.boolean "pipeline_events", default: false, null: false
t.boolean "confidential_issues_events", default: true, null: false
end end
add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
...@@ -1137,6 +1138,7 @@ ActiveRecord::Schema.define(version: 20160831223750) do ...@@ -1137,6 +1138,7 @@ ActiveRecord::Schema.define(version: 20160831223750) do
t.boolean "wiki_page_events", default: false, null: false t.boolean "wiki_page_events", default: false, null: false
t.string "token" t.string "token"
t.boolean "pipeline_events", default: false, null: false t.boolean "pipeline_events", default: false, null: false
t.boolean "confidential_issues_events", default: false, null: false
end end
add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree
......
...@@ -146,13 +146,12 @@ describe Import::BitbucketController do ...@@ -146,13 +146,12 @@ describe Import::BitbucketController do
end end
context "when a namespace with the Bitbucket user's username doesn't exist" do context "when a namespace with the Bitbucket user's username doesn't exist" do
context "when current user can create namespaces" do
it "creates the namespace" do it "creates the namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator). expect(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).and_return(double(execute: true)) to receive(:new).and_return(double(execute: true))
post :create, format: :js expect { post :create, format: :js }.to change(Namespace, :count).by(1)
expect(Namespace.where(name: other_username).first).not_to be_nil
end end
it "takes the new namespace" do it "takes the new namespace" do
...@@ -163,6 +162,28 @@ describe Import::BitbucketController do ...@@ -163,6 +162,28 @@ describe Import::BitbucketController do
post :create, format: :js post :create, format: :js
end end
end end
context "when current user can't create namespaces" do
before do
user.update_attribute(:can_create_group, false)
end
it "doesn't create the namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).and_return(double(execute: true))
expect { post :create, format: :js }.not_to change(Namespace, :count)
end
it "takes the current user's namespace" do
expect(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).with(bitbucket_repo, user.namespace, user, access_params).
and_return(double(execute: true))
post :create, format: :js
end
end
end
end end
end end
end end
...@@ -181,13 +181,12 @@ describe Import::GithubController do ...@@ -181,13 +181,12 @@ describe Import::GithubController do
end end
context "when a namespace with the GitHub user's username doesn't exist" do context "when a namespace with the GitHub user's username doesn't exist" do
context "when current user can create namespaces" do
it "creates the namespace" do it "creates the namespace" do
expect(Gitlab::GithubImport::ProjectCreator). expect(Gitlab::GithubImport::ProjectCreator).
to receive(:new).and_return(double(execute: true)) to receive(:new).and_return(double(execute: true))
post :create, format: :js expect { post :create, format: :js }.to change(Namespace, :count).by(1)
expect(Namespace.where(name: other_username).first).not_to be_nil
end end
it "takes the new namespace" do it "takes the new namespace" do
...@@ -198,6 +197,28 @@ describe Import::GithubController do ...@@ -198,6 +197,28 @@ describe Import::GithubController do
post :create, format: :js post :create, format: :js
end end
end end
context "when current user can't create namespaces" do
before do
user.update_attribute(:can_create_group, false)
end
it "doesn't create the namespace" do
expect(Gitlab::GithubImport::ProjectCreator).
to receive(:new).and_return(double(execute: true))
expect { post :create, format: :js }.not_to change(Namespace, :count)
end
it "takes the current user's namespace" do
expect(Gitlab::GithubImport::ProjectCreator).
to receive(:new).with(github_repo, user.namespace, user, access_params).
and_return(double(execute: true))
post :create, format: :js
end
end
end
end end
end end
end end
...@@ -136,13 +136,12 @@ describe Import::GitlabController do ...@@ -136,13 +136,12 @@ describe Import::GitlabController do
end end
context "when a namespace with the GitLab.com user's username doesn't exist" do context "when a namespace with the GitLab.com user's username doesn't exist" do
context "when current user can create namespaces" do
it "creates the namespace" do it "creates the namespace" do
expect(Gitlab::GitlabImport::ProjectCreator). expect(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).and_return(double(execute: true)) to receive(:new).and_return(double(execute: true))
post :create, format: :js expect { post :create, format: :js }.to change(Namespace, :count).by(1)
expect(Namespace.where(name: other_username).first).not_to be_nil
end end
it "takes the new namespace" do it "takes the new namespace" do
...@@ -153,6 +152,28 @@ describe Import::GitlabController do ...@@ -153,6 +152,28 @@ describe Import::GitlabController do
post :create, format: :js post :create, format: :js
end end
end end
context "when current user can't create namespaces" do
before do
user.update_attribute(:can_create_group, false)
end
it "doesn't create the namespace" do
expect(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).and_return(double(execute: true))
expect { post :create, format: :js }.not_to change(Namespace, :count)
end
it "takes the current user's namespace" do
expect(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).with(gitlab_repo, user.namespace, user, access_params).
and_return(double(execute: true))
post :create, format: :js
end
end
end
end end
end end
end end
require 'rails_helper' require 'rails_helper'
describe ImportHelper do describe ImportHelper do
describe '#import_project_target' do
let(:user) { create(:user) }
before do
allow(helper).to receive(:current_user).and_return(user)
end
context 'when current user can create namespaces' do
it 'returns project namespace' do
user.update_attribute(:can_create_group, true)
expect(helper.import_project_target('asd', 'vim')).to eq 'asd/vim'
end
end
context 'when current user can not create namespaces' do
it "takes the current user's namespace" do
user.update_attribute(:can_create_group, false)
expect(helper.import_project_target('asd', 'vim')).to eq "#{user.namespace_path}/vim"
end
end
end
describe '#github_project_link' do describe '#github_project_link' do
context 'when provider does not specify a custom URL' do context 'when provider does not specify a custom URL' do
it 'uses default GitHub URL' do it 'uses default GitHub URL' do
......
...@@ -18,12 +18,12 @@ describe Issues::CloseService, services: true do ...@@ -18,12 +18,12 @@ describe Issues::CloseService, services: true do
context "valid params" do context "valid params" do
before do before do
perform_enqueued_jobs do perform_enqueued_jobs do
@issue = described_class.new(project, user, {}).execute(issue) described_class.new(project, user).execute(issue)
end end
end end
it { expect(@issue).to be_valid } it { expect(issue).to be_valid }
it { expect(@issue).to be_closed } it { expect(issue).to be_closed }
it 'sends email to user2 about assign of new issue' do it 'sends email to user2 about assign of new issue' do
email = ActionMailer::Base.deliveries.last email = ActionMailer::Base.deliveries.last
...@@ -32,7 +32,7 @@ describe Issues::CloseService, services: true do ...@@ -32,7 +32,7 @@ describe Issues::CloseService, services: true do
end end
it 'creates system note about issue reassign' do it 'creates system note about issue reassign' do
note = @issue.notes.last note = issue.notes.last
expect(note.note).to include "Status changed to closed" expect(note.note).to include "Status changed to closed"
end end
...@@ -44,23 +44,43 @@ describe Issues::CloseService, services: true do ...@@ -44,23 +44,43 @@ describe Issues::CloseService, services: true do
context 'current user is not authorized to close issue' do context 'current user is not authorized to close issue' do
before do before do
perform_enqueued_jobs do perform_enqueued_jobs do
@issue = described_class.new(project, guest).execute(issue) described_class.new(project, guest).execute(issue)
end end
end end
it 'does not close the issue' do it 'does not close the issue' do
expect(@issue).to be_open expect(issue).to be_open
end end
end end
context "external issue tracker" do context 'when issue is not confidential' do
it 'executes issue hooks' do
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
expect(project).to receive(:execute_services).with(an_instance_of(Hash), :issue_hooks)
described_class.new(project, user).execute(issue)
end
end
context 'when issue is confidential' do
it 'executes confidential issue hooks' do
issue = create(:issue, :confidential, project: project)
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :confidential_issue_hooks)
expect(project).to receive(:execute_services).with(an_instance_of(Hash), :confidential_issue_hooks)
described_class.new(project, user).execute(issue)
end
end
context 'external issue tracker' do
before do before do
allow(project).to receive(:default_issues_tracker?).and_return(false) allow(project).to receive(:default_issues_tracker?).and_return(false)
@issue = described_class.new(project, user, {}).execute(issue) described_class.new(project, user).execute(issue)
end end
it { expect(@issue).to be_valid } it { expect(issue).to be_valid }
it { expect(@issue).to be_opened } it { expect(issue).to be_opened }
it { expect(todo.reload).to be_pending } it { expect(todo.reload).to be_pending }
end end
end end
......
...@@ -72,6 +72,24 @@ describe Issues::CreateService, services: true do ...@@ -72,6 +72,24 @@ describe Issues::CreateService, services: true do
expect(issue.milestone).not_to eq milestone expect(issue.milestone).not_to eq milestone
end end
end end
it 'executes issue hooks when issue is not confidential' do
opts = { title: 'Title', description: 'Description', confidential: false }
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
expect(project).to receive(:execute_services).with(an_instance_of(Hash), :issue_hooks)
described_class.new(project, user, opts).execute
end
it 'executes confidential issue hooks when issue is confidential' do
opts = { title: 'Title', description: 'Description', confidential: true }
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :confidential_issue_hooks)
expect(project).to receive(:execute_services).with(an_instance_of(Hash), :confidential_issue_hooks)
described_class.new(project, user, opts).execute
end
end end
it_behaves_like 'new issuable record that supports slash commands' it_behaves_like 'new issuable record that supports slash commands'
......
require 'spec_helper' require 'spec_helper'
describe Issues::ReopenService, services: true do describe Issues::ReopenService, services: true do
let(:guest) { create(:user) } let(:project) { create(:empty_project) }
let(:issue) { create(:issue, :closed) } let(:issue) { create(:issue, :closed, project: project) }
let(:project) { issue.project }
describe '#execute' do
context 'when user is not authorized to reopen issue' do
before do before do
guest = create(:user)
project.team << [guest, :guest] project.team << [guest, :guest]
end
describe '#execute' do
context 'current user is not authorized to reopen issue' do
before do
perform_enqueued_jobs do perform_enqueued_jobs do
@issue = described_class.new(project, guest).execute(issue) described_class.new(project, guest).execute(issue)
end end
end end
it 'does not reopen the issue' do it 'does not reopen the issue' do
expect(@issue).to be_closed expect(issue).to be_closed
end
end
context 'when user is authrized to reopen issue' do
let(:user) { create(:user) }
before do
project.team << [user, :master]
end
context 'when issue is not confidential' do
it 'executes issue hooks' do
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
expect(project).to receive(:execute_services).with(an_instance_of(Hash), :issue_hooks)
described_class.new(project, user).execute(issue)
end
end
context 'when issue is confidential' do
it 'executes confidential issue hooks' do
issue = create(:issue, :confidential, :closed, project: project)
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :confidential_issue_hooks)
expect(project).to receive(:execute_services).with(an_instance_of(Hash), :confidential_issue_hooks)
described_class.new(project, user).execute(issue)
end
end end
end end
end end
......
...@@ -23,11 +23,15 @@ describe Issues::UpdateService, services: true do ...@@ -23,11 +23,15 @@ describe Issues::UpdateService, services: true do
describe 'execute' do describe 'execute' do
def find_note(starting_with) def find_note(starting_with)
@issue.notes.find do |note| issue.notes.find do |note|
note && note.note.start_with?(starting_with) note && note.note.start_with?(starting_with)
end end
end end
def update_issue(opts)
described_class.new(project, user, opts).execute(issue)
end
context "valid params" do context "valid params" do
before do before do
opts = { opts = {
...@@ -35,23 +39,20 @@ describe Issues::UpdateService, services: true do ...@@ -35,23 +39,20 @@ describe Issues::UpdateService, services: true do
description: 'Also please fix', description: 'Also please fix',
assignee_id: user2.id, assignee_id: user2.id,
state_event: 'close', state_event: 'close',
label_ids: [label.id], label_ids: [label.id]
confidential: true
} }
perform_enqueued_jobs do perform_enqueued_jobs do
@issue = Issues::UpdateService.new(project, user, opts).execute(issue) update_issue(opts)
end end
@issue.reload
end end
it { expect(@issue).to be_valid } it { expect(issue).to be_valid }
it { expect(@issue.title).to eq('New title') } it { expect(issue.title).to eq('New title') }
it { expect(@issue.assignee).to eq(user2) } it { expect(issue.assignee).to eq(user2) }
it { expect(@issue).to be_closed } it { expect(issue).to be_closed }
it { expect(@issue.labels.count).to eq(1) } it { expect(issue.labels.count).to eq(1) }
it { expect(@issue.labels.first.title).to eq(label.name) } it { expect(issue.labels.first.title).to eq(label.name) }
it 'sends email to user2 about assign of new issue and email to user3 about issue unassignment' do it 'sends email to user2 about assign of new issue and email to user3 about issue unassignment' do
deliveries = ActionMailer::Base.deliveries deliveries = ActionMailer::Base.deliveries
...@@ -81,18 +82,35 @@ describe Issues::UpdateService, services: true do ...@@ -81,18 +82,35 @@ describe Issues::UpdateService, services: true do
expect(note).not_to be_nil expect(note).not_to be_nil
expect(note.note).to eq 'Changed title: **{-Old-} title** → **{+New+} title**' expect(note.note).to eq 'Changed title: **{-Old-} title** → **{+New+} title**'
end end
end
context 'when issue turns confidential' do
let(:opts) do
{
title: 'New title',
description: 'Also please fix',
assignee_id: user2.id,
state_event: 'close',
label_ids: [label.id],
confidential: true
}
end
it 'creates system note about confidentiality change' do it 'creates system note about confidentiality change' do
update_issue(confidential: true)
note = find_note('Made the issue confidential') note = find_note('Made the issue confidential')
expect(note).not_to be_nil expect(note).not_to be_nil
expect(note.note).to eq 'Made the issue confidential' expect(note.note).to eq 'Made the issue confidential'
end end
end
def update_issue(opts) it 'executes confidential issue hooks' do
@issue = Issues::UpdateService.new(project, user, opts).execute(issue) expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :confidential_issue_hooks)
@issue.reload expect(project).to receive(:execute_services).with(an_instance_of(Hash), :confidential_issue_hooks)
update_issue(confidential: true)
end
end end
context 'todos' do context 'todos' do
...@@ -100,7 +118,7 @@ describe Issues::UpdateService, services: true do ...@@ -100,7 +118,7 @@ describe Issues::UpdateService, services: true do
context 'when the title change' do context 'when the title change' do
before do before do
update_issue({ title: 'New title' }) update_issue(title: 'New title')
end end
it 'marks pending todos as done' do it 'marks pending todos as done' do
...@@ -110,7 +128,7 @@ describe Issues::UpdateService, services: true do ...@@ -110,7 +128,7 @@ describe Issues::UpdateService, services: true do
context 'when the description change' do context 'when the description change' do
before do before do
update_issue({ description: 'Also please fix' }) update_issue(description: 'Also please fix')
end end
it 'marks todos as done' do it 'marks todos as done' do
...@@ -120,7 +138,7 @@ describe Issues::UpdateService, services: true do ...@@ -120,7 +138,7 @@ describe Issues::UpdateService, services: true do
context 'when is reassigned' do context 'when is reassigned' do
before do before do
update_issue({ assignee: user2 }) update_issue(assignee: user2)
end end
it 'marks previous assignee todos as done' do it 'marks previous assignee todos as done' do
...@@ -144,7 +162,7 @@ describe Issues::UpdateService, services: true do ...@@ -144,7 +162,7 @@ describe Issues::UpdateService, services: true do
context 'when the milestone change' do context 'when the milestone change' do
before do before do
update_issue({ milestone: create(:milestone) }) update_issue(milestone: create(:milestone))
end end
it 'marks todos as done' do it 'marks todos as done' do
...@@ -154,7 +172,7 @@ describe Issues::UpdateService, services: true do ...@@ -154,7 +172,7 @@ describe Issues::UpdateService, services: true do
context 'when the labels change' do context 'when the labels change' do
before do before do
update_issue({ label_ids: [label.id] }) update_issue(label_ids: [label.id])
end end
it 'marks todos as done' do it 'marks todos as done' do
...@@ -165,6 +183,7 @@ describe Issues::UpdateService, services: true do ...@@ -165,6 +183,7 @@ describe Issues::UpdateService, services: true do
context 'when the issue is relabeled' do context 'when the issue is relabeled' do
let!(:non_subscriber) { create(:user) } let!(:non_subscriber) { create(:user) }
let!(:subscriber) do let!(:subscriber) do
create(:user).tap do |u| create(:user).tap do |u|
label.toggle_subscription(u) label.toggle_subscription(u)
...@@ -176,7 +195,7 @@ describe Issues::UpdateService, services: true do ...@@ -176,7 +195,7 @@ describe Issues::UpdateService, services: true do
opts = { label_ids: [label.id] } opts = { label_ids: [label.id] }
perform_enqueued_jobs do perform_enqueued_jobs do
@issue = Issues::UpdateService.new(project, user, opts).execute(issue) @issue = described_class.new(project, user, opts).execute(issue)
end end
should_email(subscriber) should_email(subscriber)
...@@ -190,7 +209,7 @@ describe Issues::UpdateService, services: true do ...@@ -190,7 +209,7 @@ describe Issues::UpdateService, services: true do
opts = { label_ids: [label.id, label2.id] } opts = { label_ids: [label.id, label2.id] }
perform_enqueued_jobs do perform_enqueued_jobs do
@issue = Issues::UpdateService.new(project, user, opts).execute(issue) @issue = described_class.new(project, user, opts).execute(issue)
end end
should_not_email(subscriber) should_not_email(subscriber)
...@@ -201,7 +220,7 @@ describe Issues::UpdateService, services: true do ...@@ -201,7 +220,7 @@ describe Issues::UpdateService, services: true do
opts = { label_ids: [label2.id] } opts = { label_ids: [label2.id] }
perform_enqueued_jobs do perform_enqueued_jobs do
@issue = Issues::UpdateService.new(project, user, opts).execute(issue) @issue = described_class.new(project, user, opts).execute(issue)
end end
should_not_email(subscriber) should_not_email(subscriber)
...@@ -210,13 +229,15 @@ describe Issues::UpdateService, services: true do ...@@ -210,13 +229,15 @@ describe Issues::UpdateService, services: true do
end end
end end
context 'when Issue has tasks' do context 'when issue has tasks' do
before { update_issue({ description: "- [ ] Task 1\n- [ ] Task 2" }) } before do
update_issue(description: "- [ ] Task 1\n- [ ] Task 2")
end
it { expect(@issue.tasks?).to eq(true) } it { expect(issue.tasks?).to eq(true) }
context 'when tasks are marked as completed' do context 'when tasks are marked as completed' do
before { update_issue({ description: "- [x] Task 1\n- [X] Task 2" }) } before { update_issue(description: "- [x] Task 1\n- [X] Task 2") }
it 'creates system note about task status change' do it 'creates system note about task status change' do
note1 = find_note('Marked the task **Task 1** as completed') note1 = find_note('Marked the task **Task 1** as completed')
...@@ -229,8 +250,8 @@ describe Issues::UpdateService, services: true do ...@@ -229,8 +250,8 @@ describe Issues::UpdateService, services: true do
context 'when tasks are marked as incomplete' do context 'when tasks are marked as incomplete' do
before do before do
update_issue({ description: "- [x] Task 1\n- [X] Task 2" }) update_issue(description: "- [x] Task 1\n- [X] Task 2")
update_issue({ description: "- [ ] Task 1\n- [ ] Task 2" }) update_issue(description: "- [ ] Task 1\n- [ ] Task 2")
end end
it 'creates system note about task status change' do it 'creates system note about task status change' do
...@@ -244,8 +265,8 @@ describe Issues::UpdateService, services: true do ...@@ -244,8 +265,8 @@ describe Issues::UpdateService, services: true do
context 'when tasks position has been modified' do context 'when tasks position has been modified' do
before do before do
update_issue({ description: "- [x] Task 1\n- [X] Task 2" }) update_issue(description: "- [x] Task 1\n- [X] Task 2")
update_issue({ description: "- [x] Task 1\n- [ ] Task 3\n- [ ] Task 2" }) update_issue(description: "- [x] Task 1\n- [ ] Task 3\n- [ ] Task 2")
end end
it 'does not create a system note' do it 'does not create a system note' do
...@@ -257,8 +278,8 @@ describe Issues::UpdateService, services: true do ...@@ -257,8 +278,8 @@ describe Issues::UpdateService, services: true do
context 'when a Task list with a completed item is totally replaced' do context 'when a Task list with a completed item is totally replaced' do
before do before do
update_issue({ description: "- [ ] Task 1\n- [X] Task 2" }) update_issue(description: "- [ ] Task 1\n- [X] Task 2")
update_issue({ description: "- [ ] One\n- [ ] Two\n- [ ] Three" }) update_issue(description: "- [ ] One\n- [ ] Two\n- [ ] Three")
end end
it 'does not create a system note referencing the position the old item' do it 'does not create a system note referencing the position the old item' do
...@@ -269,7 +290,7 @@ describe Issues::UpdateService, services: true do ...@@ -269,7 +290,7 @@ describe Issues::UpdateService, services: true do
it 'does not generate a new note at all' do it 'does not generate a new note at all' do
expect do expect do
update_issue({ description: "- [ ] One\n- [ ] Two\n- [ ] Three" }) update_issue(description: "- [ ] One\n- [ ] Two\n- [ ] Three")
end.not_to change { Note.count } end.not_to change { Note.count }
end end
end end
...@@ -277,7 +298,7 @@ describe Issues::UpdateService, services: true do ...@@ -277,7 +298,7 @@ describe Issues::UpdateService, services: true do
context 'updating labels' do context 'updating labels' do
let(:label3) { create(:label, project: project) } let(:label3) { create(:label, project: project) }
let(:result) { Issues::UpdateService.new(project, user, params).execute(issue).reload } let(:result) { described_class.new(project, user, params).execute(issue).reload }
context 'when add_label_ids and label_ids are passed' do context 'when add_label_ids and label_ids are passed' do
let(:params) { { label_ids: [label.id], add_label_ids: [label3.id] } } let(:params) { { label_ids: [label.id], add_label_ids: [label3.id] } }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment