Remove permanent redirects
Removes permanent redirects, this means that redirects will only be possible as long as the old route isn't taken by a new project/group.
This commit is contained in:
parent
7ea08566f3
commit
ce69419a60
|
@ -17,32 +17,4 @@ class RedirectRoute < ActiveRecord::Base
|
||||||
|
|
||||||
where(wheres, path, "#{sanitize_sql_like(path)}/%")
|
where(wheres, path, "#{sanitize_sql_like(path)}/%")
|
||||||
end
|
end
|
||||||
|
|
||||||
scope :permanent, -> do
|
|
||||||
if column_permanent_exists?
|
|
||||||
where(permanent: true)
|
|
||||||
else
|
|
||||||
none
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
scope :temporary, -> do
|
|
||||||
if column_permanent_exists?
|
|
||||||
where(permanent: [false, nil])
|
|
||||||
else
|
|
||||||
all
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
default_value_for :permanent, false
|
|
||||||
|
|
||||||
def permanent=(value)
|
|
||||||
if self.class.column_permanent_exists?
|
|
||||||
super
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.column_permanent_exists?
|
|
||||||
ActiveRecord::Base.connection.column_exists?(:redirect_routes, :permanent)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,8 +10,6 @@ class Route < ActiveRecord::Base
|
||||||
presence: true,
|
presence: true,
|
||||||
uniqueness: { case_sensitive: false }
|
uniqueness: { case_sensitive: false }
|
||||||
|
|
||||||
validate :ensure_permanent_paths, if: :path_changed?
|
|
||||||
|
|
||||||
before_validation :delete_conflicting_orphaned_routes
|
before_validation :delete_conflicting_orphaned_routes
|
||||||
after_create :delete_conflicting_redirects
|
after_create :delete_conflicting_redirects
|
||||||
after_update :delete_conflicting_redirects, if: :path_changed?
|
after_update :delete_conflicting_redirects, if: :path_changed?
|
||||||
|
@ -45,7 +43,7 @@ class Route < ActiveRecord::Base
|
||||||
# We are not calling route.delete_conflicting_redirects here, in hopes
|
# We are not calling route.delete_conflicting_redirects here, in hopes
|
||||||
# of avoiding deadlocks. The parent (self, in this method) already
|
# of avoiding deadlocks. The parent (self, in this method) already
|
||||||
# called it, which deletes conflicts for all descendants.
|
# called it, which deletes conflicts for all descendants.
|
||||||
route.create_redirect(old_path, permanent: permanent_redirect?) if attributes[:path]
|
route.create_redirect(old_path) if attributes[:path]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -55,31 +53,17 @@ class Route < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def conflicting_redirects
|
def conflicting_redirects
|
||||||
RedirectRoute.temporary.matching_path_and_descendants(path)
|
RedirectRoute.matching_path_and_descendants(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_redirect(path, permanent: false)
|
def create_redirect(path)
|
||||||
RedirectRoute.create(source: source, path: path, permanent: permanent)
|
RedirectRoute.create(source: source, path: path)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_redirect_for_old_path
|
def create_redirect_for_old_path
|
||||||
create_redirect(path_was, permanent: permanent_redirect?) if path_changed?
|
create_redirect(path_was) if path_changed?
|
||||||
end
|
|
||||||
|
|
||||||
def permanent_redirect?
|
|
||||||
source_type != "Project"
|
|
||||||
end
|
|
||||||
|
|
||||||
def ensure_permanent_paths
|
|
||||||
return if path.nil?
|
|
||||||
|
|
||||||
errors.add(:path, "has been taken before") if conflicting_redirect_exists?
|
|
||||||
end
|
|
||||||
|
|
||||||
def conflicting_redirect_exists?
|
|
||||||
RedirectRoute.permanent.matching_path_and_descendants(path).exists?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_conflicting_orphaned_routes
|
def delete_conflicting_orphaned_routes
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Don't create permanent redirect routes
|
||||||
|
merge_request: 17521
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -9,20 +9,16 @@ module Gitlab
|
||||||
super(project, user, protocol)
|
super(project, user, protocol)
|
||||||
end
|
end
|
||||||
|
|
||||||
def message(rejected: false)
|
def message
|
||||||
<<~MESSAGE
|
<<~MESSAGE
|
||||||
Project '#{redirected_path}' was moved to '#{project.full_path}'.
|
Project '#{redirected_path}' was moved to '#{project.full_path}'.
|
||||||
|
|
||||||
Please update your Git remote:
|
Please update your Git remote:
|
||||||
|
|
||||||
#{remote_url_message(rejected)}
|
git remote set-url origin #{url_to_repo}
|
||||||
MESSAGE
|
MESSAGE
|
||||||
end
|
end
|
||||||
|
|
||||||
def permanent_redirect?
|
|
||||||
RedirectRoute.permanent.exists?(path: redirected_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :redirected_path
|
attr_reader :redirected_path
|
||||||
|
@ -30,18 +26,6 @@ module Gitlab
|
||||||
def self.message_key(user_id, project_id)
|
def self.message_key(user_id, project_id)
|
||||||
"#{REDIRECT_NAMESPACE}:#{user_id}:#{project_id}"
|
"#{REDIRECT_NAMESPACE}:#{user_id}:#{project_id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def remote_url_message(rejected)
|
|
||||||
if rejected
|
|
||||||
"git remote set-url origin #{url_to_repo} and try again."
|
|
||||||
else
|
|
||||||
"git remote set-url origin #{url_to_repo}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def url
|
|
||||||
protocol == 'ssh' ? project.ssh_url_to_repo : project.http_url_to_repo
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,7 +53,7 @@ module Gitlab
|
||||||
ensure_project_on_push!(cmd, changes)
|
ensure_project_on_push!(cmd, changes)
|
||||||
|
|
||||||
check_project_accessibility!
|
check_project_accessibility!
|
||||||
check_project_moved!
|
add_project_moved_message!
|
||||||
check_repository_existence!
|
check_repository_existence!
|
||||||
|
|
||||||
case cmd
|
case cmd
|
||||||
|
@ -125,16 +125,12 @@ module Gitlab
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_project_moved!
|
def add_project_moved_message!
|
||||||
return if redirected_path.nil?
|
return if redirected_path.nil?
|
||||||
|
|
||||||
project_moved = Checks::ProjectMoved.new(project, user, protocol, redirected_path)
|
project_moved = Checks::ProjectMoved.new(project, user, protocol, redirected_path)
|
||||||
|
|
||||||
if project_moved.permanent_redirect?
|
project_moved.add_message
|
||||||
project_moved.add_message
|
|
||||||
else
|
|
||||||
raise ProjectMovedError, project_moved.message(rejected: true)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_command_disabled!(cmd)
|
def check_command_disabled!(cmd)
|
||||||
|
|
|
@ -2,14 +2,5 @@ FactoryBot.define do
|
||||||
factory :redirect_route do
|
factory :redirect_route do
|
||||||
sequence(:path) { |n| "redirect#{n}" }
|
sequence(:path) { |n| "redirect#{n}" }
|
||||||
source factory: :group
|
source factory: :group
|
||||||
permanent false
|
|
||||||
|
|
||||||
trait :permanent do
|
|
||||||
permanent true
|
|
||||||
end
|
|
||||||
|
|
||||||
trait :temporary do
|
|
||||||
permanent false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -44,44 +44,17 @@ describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#message' do
|
describe '#message' do
|
||||||
context 'when the push is rejected' do
|
it 'returns a redirect message' do
|
||||||
it 'returns a redirect message telling the user to try again' do
|
project_moved = described_class.new(project, user, 'http', 'foo/bar')
|
||||||
project_moved = described_class.new(project, user, 'http', 'foo/bar')
|
message = <<~MSG
|
||||||
message = "Project 'foo/bar' was moved to '#{project.full_path}'." +
|
Project 'foo/bar' was moved to '#{project.full_path}'.
|
||||||
"\n\nPlease update your Git remote:" +
|
|
||||||
"\n\n git remote set-url origin #{project.http_url_to_repo} and try again.\n"
|
|
||||||
|
|
||||||
expect(project_moved.message(rejected: true)).to eq(message)
|
Please update your Git remote:
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the push is not rejected' do
|
git remote set-url origin #{project.http_url_to_repo}
|
||||||
it 'returns a redirect message' do
|
MSG
|
||||||
project_moved = described_class.new(project, user, 'http', 'foo/bar')
|
|
||||||
message = "Project 'foo/bar' was moved to '#{project.full_path}'." +
|
|
||||||
"\n\nPlease update your Git remote:" +
|
|
||||||
"\n\n git remote set-url origin #{project.http_url_to_repo}\n"
|
|
||||||
|
|
||||||
expect(project_moved.message).to eq(message)
|
expect(project_moved.message).to eq(message)
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#permanent_redirect?' do
|
|
||||||
context 'with a permanent RedirectRoute' do
|
|
||||||
it 'returns true' do
|
|
||||||
project.route.create_redirect('foo/bar', permanent: true)
|
|
||||||
project_moved = described_class.new(project, user, 'http', 'foo/bar')
|
|
||||||
expect(project_moved.permanent_redirect?).to be_truthy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'without a permanent RedirectRoute' do
|
|
||||||
it 'returns false' do
|
|
||||||
project.route.create_redirect('foo/bar')
|
|
||||||
project_moved = described_class.new(project, user, 'http', 'foo/bar')
|
|
||||||
expect(project_moved.permanent_redirect?).to be_falsy
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -240,14 +240,21 @@ describe Gitlab::GitAccess do
|
||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'check_project_moved' do
|
shared_examples 'check_project_moved' do
|
||||||
it 'enqueues a redirected message' do
|
it 'enqueues a redirected message for pushing' do
|
||||||
push_access_check
|
push_access_check
|
||||||
|
|
||||||
expect(Gitlab::Checks::ProjectMoved.fetch_message(user.id, project.id)).not_to be_nil
|
expect(Gitlab::Checks::ProjectMoved.fetch_message(user.id, project.id)).not_to be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'allows push and pull access' do
|
||||||
|
aggregate_failures do
|
||||||
|
expect { push_access_check }.not_to raise_error
|
||||||
|
expect { pull_access_check }.not_to raise_error
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#check_project_moved!', :clean_gitlab_redis_shared_state do
|
describe '#add_project_moved_message!', :clean_gitlab_redis_shared_state do
|
||||||
before do
|
before do
|
||||||
project.add_master(user)
|
project.add_master(user)
|
||||||
end
|
end
|
||||||
|
@ -261,62 +268,18 @@ describe Gitlab::GitAccess do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a permanent redirect and ssh protocol' do
|
context 'with a redirect and ssh protocol' do
|
||||||
let(:redirected_path) { 'some/other-path' }
|
let(:redirected_path) { 'some/other-path' }
|
||||||
|
|
||||||
before do
|
|
||||||
allow_any_instance_of(Gitlab::Checks::ProjectMoved).to receive(:permanent_redirect?).and_return(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'allows push and pull access' do
|
|
||||||
aggregate_failures do
|
|
||||||
expect { push_access_check }.not_to raise_error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'check_project_moved'
|
it_behaves_like 'check_project_moved'
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a permanent redirect and http protocol' do
|
context 'with a redirect and http protocol' do
|
||||||
let(:redirected_path) { 'some/other-path' }
|
let(:redirected_path) { 'some/other-path' }
|
||||||
let(:protocol) { 'http' }
|
let(:protocol) { 'http' }
|
||||||
|
|
||||||
before do
|
|
||||||
allow_any_instance_of(Gitlab::Checks::ProjectMoved).to receive(:permanent_redirect?).and_return(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'allows_push and pull access' do
|
|
||||||
aggregate_failures do
|
|
||||||
expect { push_access_check }.not_to raise_error
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it_behaves_like 'check_project_moved'
|
it_behaves_like 'check_project_moved'
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a temporal redirect and ssh protocol' do
|
|
||||||
let(:redirected_path) { 'some/other-path' }
|
|
||||||
|
|
||||||
it 'blocks push and pull access' do
|
|
||||||
aggregate_failures do
|
|
||||||
expect { push_access_check }.to raise_error(described_class::ProjectMovedError, /Project '#{redirected_path}' was moved to '#{project.full_path}'/)
|
|
||||||
expect { push_access_check }.to raise_error(described_class::ProjectMovedError, /git remote set-url origin #{project.ssh_url_to_repo}/)
|
|
||||||
|
|
||||||
expect { pull_access_check }.to raise_error(described_class::ProjectMovedError, /Project '#{redirected_path}' was moved to '#{project.full_path}'/)
|
|
||||||
expect { pull_access_check }.to raise_error(described_class::ProjectMovedError, /git remote set-url origin #{project.ssh_url_to_repo}/)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with a temporal redirect and http protocol' do
|
|
||||||
let(:redirected_path) { 'some/other-path' }
|
|
||||||
let(:protocol) { 'http' }
|
|
||||||
|
|
||||||
it 'does not allow to push and pull access' do
|
|
||||||
expect { push_access_check }.to raise_error(described_class::ProjectMovedError, /git remote set-url origin #{project.http_url_to_repo}/)
|
|
||||||
expect { pull_access_check }.to raise_error(described_class::ProjectMovedError, /git remote set-url origin #{project.http_url_to_repo}/)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#check_authentication_abilities!' do
|
describe '#check_authentication_abilities!' do
|
||||||
|
|
|
@ -16,66 +16,6 @@ describe Route do
|
||||||
it { is_expected.to validate_presence_of(:source) }
|
it { is_expected.to validate_presence_of(:source) }
|
||||||
it { is_expected.to validate_presence_of(:path) }
|
it { is_expected.to validate_presence_of(:path) }
|
||||||
it { is_expected.to validate_uniqueness_of(:path).case_insensitive }
|
it { is_expected.to validate_uniqueness_of(:path).case_insensitive }
|
||||||
|
|
||||||
describe '#ensure_permanent_paths' do
|
|
||||||
context 'when the route is not yet persisted' do
|
|
||||||
let(:new_route) { described_class.new(path: 'foo', source: build(:group)) }
|
|
||||||
|
|
||||||
context 'when permanent conflicting redirects exist' do
|
|
||||||
it 'is invalid' do
|
|
||||||
redirect = build(:redirect_route, :permanent, path: 'foo/bar/baz')
|
|
||||||
redirect.save!(validate: false)
|
|
||||||
|
|
||||||
expect(new_route.valid?).to be_falsey
|
|
||||||
expect(new_route.errors.first[1]).to eq('has been taken before')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when no permanent conflicting redirects exist' do
|
|
||||||
it 'is valid' do
|
|
||||||
expect(new_route.valid?).to be_truthy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when path has changed' do
|
|
||||||
before do
|
|
||||||
route.path = 'foo'
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when permanent conflicting redirects exist' do
|
|
||||||
it 'is invalid' do
|
|
||||||
redirect = build(:redirect_route, :permanent, path: 'foo/bar/baz')
|
|
||||||
redirect.save!(validate: false)
|
|
||||||
|
|
||||||
expect(route.valid?).to be_falsey
|
|
||||||
expect(route.errors.first[1]).to eq('has been taken before')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when no permanent conflicting redirects exist' do
|
|
||||||
it 'is valid' do
|
|
||||||
expect(route.valid?).to be_truthy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when path has not changed' do
|
|
||||||
context 'when permanent conflicting redirects exist' do
|
|
||||||
it 'is valid' do
|
|
||||||
redirect = build(:redirect_route, :permanent, path: 'git_lab/foo/bar')
|
|
||||||
redirect.save!(validate: false)
|
|
||||||
|
|
||||||
expect(route.valid?).to be_truthy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
context 'when no permanent conflicting redirects exist' do
|
|
||||||
it 'is valid' do
|
|
||||||
expect(route.valid?).to be_truthy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'callbacks' do
|
describe 'callbacks' do
|
||||||
|
@ -211,43 +151,31 @@ describe Route do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the source is a Project' do
|
context 'when the source is a Project' do
|
||||||
it 'creates a temporal RedirectRoute' do
|
it 'creates a RedirectRoute' do
|
||||||
project = create(:project)
|
project = create(:project)
|
||||||
route = project.route
|
route = project.route
|
||||||
redirect_route = route.create_redirect('foo')
|
redirect_route = route.create_redirect('foo')
|
||||||
expect(redirect_route.permanent?).to be_falsy
|
expect(redirect_route).not_to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the source is not a project' do
|
context 'when the source is not a project' do
|
||||||
it 'creates a permanent RedirectRoute' do
|
it 'creates a RedirectRoute' do
|
||||||
redirect_route = route.create_redirect('foo', permanent: true)
|
redirect_route = route.create_redirect('foo')
|
||||||
expect(redirect_route.permanent?).to be_truthy
|
expect(redirect_route).not_to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#delete_conflicting_redirects' do
|
describe '#delete_conflicting_redirects' do
|
||||||
context 'with permanent redirect' do
|
let(:route) { create(:project).route }
|
||||||
it 'does not delete the redirect' do
|
|
||||||
route.create_redirect("#{route.path}/foo", permanent: true)
|
|
||||||
|
|
||||||
expect do
|
it 'deletes the redirect' do
|
||||||
route.delete_conflicting_redirects
|
route.create_redirect("#{route.path}/foo")
|
||||||
end.not_to change { RedirectRoute.count }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with temporal redirect' do
|
expect do
|
||||||
let(:route) { create(:project).route }
|
route.delete_conflicting_redirects
|
||||||
|
end.to change { RedirectRoute.count }.by(-1)
|
||||||
it 'deletes the redirect' do
|
|
||||||
route.create_redirect("#{route.path}/foo")
|
|
||||||
|
|
||||||
expect do
|
|
||||||
route.delete_conflicting_redirects
|
|
||||||
end.to change { RedirectRoute.count }.by(-1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a redirect route with the same path exists' do
|
context 'when a redirect route with the same path exists' do
|
||||||
|
@ -289,31 +217,18 @@ describe Route do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#conflicting_redirects' do
|
describe '#conflicting_redirects' do
|
||||||
|
let(:route) { create(:project).route }
|
||||||
|
|
||||||
it 'returns an ActiveRecord::Relation' do
|
it 'returns an ActiveRecord::Relation' do
|
||||||
expect(route.conflicting_redirects).to be_an(ActiveRecord::Relation)
|
expect(route.conflicting_redirects).to be_an(ActiveRecord::Relation)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with permanent redirects' do
|
it 'returns the redirect routes' do
|
||||||
it 'does not return anything' do
|
redirect1 = route.create_redirect("#{route.path}/foo")
|
||||||
route.create_redirect("#{route.path}/foo", permanent: true)
|
redirect2 = route.create_redirect("#{route.path}/foo/bar")
|
||||||
route.create_redirect("#{route.path}/foo/bar", permanent: true)
|
redirect3 = route.create_redirect("#{route.path}/baz/quz")
|
||||||
route.create_redirect("#{route.path}/baz/quz", permanent: true)
|
|
||||||
|
|
||||||
expect(route.conflicting_redirects).to be_empty
|
expect(route.conflicting_redirects).to match_array([redirect1, redirect2, redirect3])
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'with temporal redirects' do
|
|
||||||
let(:route) { create(:project).route }
|
|
||||||
|
|
||||||
it 'returns the redirect routes' do
|
|
||||||
route = create(:project).route
|
|
||||||
redirect1 = route.create_redirect("#{route.path}/foo")
|
|
||||||
redirect2 = route.create_redirect("#{route.path}/foo/bar")
|
|
||||||
redirect3 = route.create_redirect("#{route.path}/baz/quz")
|
|
||||||
|
|
||||||
expect(route.conflicting_redirects).to match_array([redirect1, redirect2, redirect3])
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a redirect route with the same path exists' do
|
context 'when a redirect route with the same path exists' do
|
||||||
|
@ -348,44 +263,6 @@ describe Route do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#conflicting_redirect_exists?" do
|
|
||||||
context 'when a conflicting redirect exists' do
|
|
||||||
let(:group1) { create(:group, path: 'foo') }
|
|
||||||
let(:group2) { create(:group, path: 'baz') }
|
|
||||||
|
|
||||||
it 'should not be saved' do
|
|
||||||
group1.path = 'bar'
|
|
||||||
group1.save
|
|
||||||
|
|
||||||
group2.path = 'foo'
|
|
||||||
|
|
||||||
expect(group2.save).to be_falsy
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should return an error on path' do
|
|
||||||
group1.path = 'bar'
|
|
||||||
group1.save
|
|
||||||
|
|
||||||
group2.path = 'foo'
|
|
||||||
group2.valid?
|
|
||||||
expect(group2.errors[:path]).to eq(['has been taken before'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when a conflicting redirect does not exist' do
|
|
||||||
let(:project1) { create(:project, path: 'foo') }
|
|
||||||
let(:project2) { create(:project, path: 'baz') }
|
|
||||||
|
|
||||||
it 'should be saved' do
|
|
||||||
project1.path = 'bar'
|
|
||||||
project1.save
|
|
||||||
|
|
||||||
project2.path = 'foo'
|
|
||||||
expect(project2.save).to be_truthy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#delete_conflicting_orphaned_routes' do
|
describe '#delete_conflicting_orphaned_routes' do
|
||||||
context 'when there is a conflicting route' do
|
context 'when there is a conflicting route' do
|
||||||
let!(:conflicting_group) { create(:group, path: 'foo') }
|
let!(:conflicting_group) { create(:group, path: 'foo') }
|
||||||
|
|
|
@ -126,23 +126,6 @@ describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the username was used by another user before' do
|
|
||||||
let(:username) { 'foo' }
|
|
||||||
let!(:other_user) { create(:user, username: username) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
other_user.username = 'bar'
|
|
||||||
other_user.save!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'is invalid' do
|
|
||||||
user = build(:user, username: username)
|
|
||||||
|
|
||||||
expect(user).not_to be_valid
|
|
||||||
expect(user.errors.full_messages).to eq(['Username has been taken before'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the username is in use by another user' do
|
context 'when the username is in use by another user' do
|
||||||
let(:username) { 'foo' }
|
let(:username) { 'foo' }
|
||||||
let!(:other_user) { create(:user, username: username) }
|
let!(:other_user) { create(:user, username: username) }
|
||||||
|
@ -2699,27 +2682,19 @@ describe User do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#username_previously_taken?" do
|
context 'changing a username' do
|
||||||
let(:user1) { create(:user, username: 'foo') }
|
let(:user) { create(:user, username: 'foo') }
|
||||||
|
|
||||||
context 'when the username has been taken before' do
|
it 'creates a redirect route' do
|
||||||
before do
|
expect { user.update!(username: 'bar') }
|
||||||
user1.username = 'bar'
|
.to change { RedirectRoute.where(path: 'foo').count }.by(1)
|
||||||
user1.save!
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should raise an ActiveRecord::RecordInvalid exception' do
|
|
||||||
user2 = build(:user, username: 'foo')
|
|
||||||
expect { user2.save! }.to raise_error(ActiveRecord::RecordInvalid, /Username has been taken before/)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the username has not been taken before' do
|
it 'deletes the redirect when a user with the old username was created' do
|
||||||
it 'should be valid' do
|
user.update!(username: 'bar')
|
||||||
expect(RedirectRoute.count).to eq(0)
|
|
||||||
user2 = build(:user, username: 'baz')
|
expect { create(:user, username: 'foo') }
|
||||||
expect(user2).to be_valid
|
.to change { RedirectRoute.where(path: 'foo').count }.by(-1)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -344,20 +344,11 @@ describe 'Git HTTP requests' do
|
||||||
context 'and the user requests a redirected path' do
|
context 'and the user requests a redirected path' do
|
||||||
let!(:redirect) { project.route.create_redirect('foo/bar') }
|
let!(:redirect) { project.route.create_redirect('foo/bar') }
|
||||||
let(:path) { "#{redirect.path}.git" }
|
let(:path) { "#{redirect.path}.git" }
|
||||||
let(:project_moved_message) do
|
|
||||||
<<-MSG.strip_heredoc
|
|
||||||
Project '#{redirect.path}' was moved to '#{project.full_path}'.
|
|
||||||
|
|
||||||
Please update your Git remote:
|
it 'downloads get status 200 for redirects' do
|
||||||
|
|
||||||
git remote set-url origin #{project.http_url_to_repo} and try again.
|
|
||||||
MSG
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'downloads get status 404 with "project was moved" message' do
|
|
||||||
clone_get(path, {})
|
clone_get(path, {})
|
||||||
expect(response).to have_gitlab_http_status(:not_found)
|
|
||||||
expect(response.body).to match(project_moved_message)
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -559,20 +550,19 @@ describe 'Git HTTP requests' do
|
||||||
|
|
||||||
Please update your Git remote:
|
Please update your Git remote:
|
||||||
|
|
||||||
git remote set-url origin #{project.http_url_to_repo} and try again.
|
git remote set-url origin #{project.http_url_to_repo}.
|
||||||
MSG
|
MSG
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'downloads get status 404 with "project was moved" message' do
|
it 'downloads get status 200' do
|
||||||
clone_get(path, env)
|
clone_get(path, env)
|
||||||
expect(response).to have_gitlab_http_status(:not_found)
|
|
||||||
expect(response.body).to match(project_moved_message)
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'uploads get status 404 with "project was moved" message' do
|
it 'uploads get status 404 with "project was moved" message' do
|
||||||
upload(path, env) do |response|
|
upload(path, env) do |response|
|
||||||
expect(response).to have_gitlab_http_status(:not_found)
|
expect(response).to have_gitlab_http_status(:ok)
|
||||||
expect(response.body).to match(project_moved_message)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -222,8 +222,8 @@ describe Groups::TransferService, :postgresql do
|
||||||
expect(new_parent_group.children.first).to eq(group)
|
expect(new_parent_group.children.first).to eq(group)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create a permanent redirect for the group' do
|
it 'should create a redirect for the group' do
|
||||||
expect(group.redirect_routes.permanent.count).to eq(1)
|
expect(group.redirect_routes.count).to eq(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -243,10 +243,10 @@ describe Groups::TransferService, :postgresql do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create permanent redirects for the subgroups' do
|
it 'should create redirects for the subgroups' do
|
||||||
expect(group.redirect_routes.permanent.count).to eq(1)
|
expect(group.redirect_routes.count).to eq(1)
|
||||||
expect(subgroup1.redirect_routes.permanent.count).to eq(1)
|
expect(subgroup1.redirect_routes.count).to eq(1)
|
||||||
expect(subgroup2.redirect_routes.permanent.count).to eq(1)
|
expect(subgroup2.redirect_routes.count).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the new parent has a higher visibility than the children' do
|
context 'when the new parent has a higher visibility than the children' do
|
||||||
|
@ -287,9 +287,9 @@ describe Groups::TransferService, :postgresql do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create permanent redirects for the projects' do
|
it 'should create permanent redirects for the projects' do
|
||||||
expect(group.redirect_routes.permanent.count).to eq(1)
|
expect(group.redirect_routes.count).to eq(1)
|
||||||
expect(project1.redirect_routes.permanent.count).to eq(1)
|
expect(project1.redirect_routes.count).to eq(1)
|
||||||
expect(project2.redirect_routes.permanent.count).to eq(1)
|
expect(project2.redirect_routes.count).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the new parent has a higher visibility than the projects' do
|
context 'when the new parent has a higher visibility than the projects' do
|
||||||
|
@ -338,12 +338,12 @@ describe Groups::TransferService, :postgresql do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create permanent redirect for the subgroups and projects' do
|
it 'should create redirect for the subgroups and projects' do
|
||||||
expect(group.redirect_routes.permanent.count).to eq(1)
|
expect(group.redirect_routes.count).to eq(1)
|
||||||
expect(subgroup1.redirect_routes.permanent.count).to eq(1)
|
expect(subgroup1.redirect_routes.count).to eq(1)
|
||||||
expect(subgroup2.redirect_routes.permanent.count).to eq(1)
|
expect(subgroup2.redirect_routes.count).to eq(1)
|
||||||
expect(project1.redirect_routes.permanent.count).to eq(1)
|
expect(project1.redirect_routes.count).to eq(1)
|
||||||
expect(project2.redirect_routes.permanent.count).to eq(1)
|
expect(project2.redirect_routes.count).to eq(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -380,12 +380,12 @@ describe Groups::TransferService, :postgresql do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should create permanent redirect for the subgroups and projects' do
|
it 'should create redirect for the subgroups and projects' do
|
||||||
expect(group.redirect_routes.permanent.count).to eq(1)
|
expect(group.redirect_routes.count).to eq(1)
|
||||||
expect(project1.redirect_routes.permanent.count).to eq(1)
|
expect(project1.redirect_routes.count).to eq(1)
|
||||||
expect(subgroup1.redirect_routes.permanent.count).to eq(1)
|
expect(subgroup1.redirect_routes.count).to eq(1)
|
||||||
expect(nested_subgroup.redirect_routes.permanent.count).to eq(1)
|
expect(nested_subgroup.redirect_routes.count).to eq(1)
|
||||||
expect(nested_project.redirect_routes.permanent.count).to eq(1)
|
expect(nested_project.redirect_routes.count).to eq(1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue