Unverified Commit 83232be0 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets
Browse files

Add nested groups support on data level



* add parent_id field to namespaces table to store relation with nested groups
* create routes table to keep information about full path of every group and project
* project/group lookup by full path from routes table
Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parent 8b24814cd582
......@@ -10,6 +10,13 @@
it { expect(subject.matches?(request)).to be_truthy }
end
context 'valid request for nested group' do
let!(:nested_group) { create(:group, path: 'nested', parent: group) }
let!(:request) { build_request('gitlab/nested') }
it { expect(subject.matches?(request)).to be_truthy }
end
context 'invalid request' do
let(:request) { build_request('foo') }
......
......@@ -188,6 +188,7 @@ project:
- project_feature
- authorized_users
- project_authorizations
- route
award_emoji:
- awardable
- user
......
require 'spec_helper'
describe Group, 'Routable' do
let!(:group) { create(:group) }
describe 'Associations' do
it { is_expected.to have_one(:route).dependent(:destroy) }
end
describe 'Callbacks' do
it 'creates route record on create' do
expect(group.route.path).to eq(group.path)
end
it 'updates route record on path change' do
group.update_attributes(path: 'wow')
expect(group.route.path).to eq('wow')
end
it 'ensure route path uniqueness across different objects' do
create(:group, parent: group, path: 'xyz')
duplicate = build(:project, namespace: group, path: 'xyz')
expect { duplicate.save! }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Route path has already been taken, Route is invalid')
end
end
describe '.find_by_full_path' do
let!(:nested_group) { create(:group, parent: group) }
it { expect(described_class.find_by_full_path(group.to_param)).to eq(group) }
it { expect(described_class.find_by_full_path(group.to_param.upcase)).to eq(group) }
it { expect(described_class.find_by_full_path(nested_group.to_param)).to eq(nested_group) }
it { expect(described_class.find_by_full_path('unknown')).to eq(nil) }
end
describe '.where_paths_in' do
context 'without any paths' do
it 'returns an empty relation' do
expect(described_class.where_paths_in([])).to eq([])
end
end
context 'without any valid paths' do
it 'returns an empty relation' do
expect(described_class.where_paths_in(%w[unknown])).to eq([])
end
end
context 'with valid paths' do
let!(:nested_group) { create(:group, parent: group) }
it 'returns the projects matching the paths' do
result = described_class.where_paths_in([group.to_param, nested_group.to_param])
expect(result).to contain_exactly(group, nested_group)
end
it 'returns projects regardless of the casing of paths' do
result = described_class.where_paths_in([group.to_param.upcase, nested_group.to_param.upcase])
expect(result).to contain_exactly(group, nested_group)
end
end
end
end
......@@ -117,4 +117,12 @@
expect(Namespace.clean_path("--%+--valid_*&%name=.git.%.atom.atom.@email.com")).to eq("valid_name")
end
end
describe '#full_path' do
let(:group) { create(:group) }
let(:nested_group) { create(:group, parent: group) }
it { expect(group.full_path).to eq(group.path) }
it { expect(nested_group.full_path).to eq("#{group.path}/#{nested_group.path}") }
end
end
......@@ -474,35 +474,6 @@
end
end
describe '.find_with_namespace' do
context 'with namespace' do
before do
@group = create :group, name: 'gitlab'
@project = create(:project, name: 'gitlabhq', namespace: @group)
end
it { expect(Project.find_with_namespace('gitlab/gitlabhq')).to eq(@project) }
it { expect(Project.find_with_namespace('GitLab/GitlabHQ')).to eq(@project) }
it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil }
end
context 'when multiple projects using a similar name exist' do
let(:group) { create(:group, name: 'gitlab') }
let!(:project1) do
create(:empty_project, name: 'gitlab1', path: 'gitlab', namespace: group)
end
let!(:project2) do
create(:empty_project, name: 'gitlab2', path: 'GITLAB', namespace: group)
end
it 'returns the row where the path matches literally' do
expect(Project.find_with_namespace('gitlab/GITLAB')).to eq(project2)
end
end
end
describe '#to_param' do
context 'with namespace' do
before do
......@@ -1544,39 +1515,6 @@ def create_build(new_pipeline = pipeline, name = 'test')
end
end
describe '.where_paths_in' do
context 'without any paths' do
it 'returns an empty relation' do
expect(Project.where_paths_in([])).to eq([])
end
end
context 'without any valid paths' do
it 'returns an empty relation' do
expect(Project.where_paths_in(%w[foo])).to eq([])
end
end
context 'with valid paths' do
let!(:project1) { create(:project) }
let!(:project2) { create(:project) }
it 'returns the projects matching the paths' do
projects = Project.where_paths_in([project1.path_with_namespace,
project2.path_with_namespace])
expect(projects).to contain_exactly(project1, project2)
end
it 'returns projects regardless of the casing of paths' do
projects = Project.where_paths_in([project1.path_with_namespace.upcase,
project2.path_with_namespace.upcase])
expect(projects).to contain_exactly(project1, project2)
end
end
end
describe 'change_head' do
let(:project) { create(:project) }
......
require 'spec_helper'
describe Route, models: true do
let!(:group) { create(:group) }
let!(:route) { group.route }
describe 'relationships' do
it { is_expected.to belong_to(:source) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:source) }
it { is_expected.to validate_presence_of(:path) }
it { is_expected.to validate_uniqueness_of(:path) }
end
describe '#rename_children' do
let!(:nested_group) { create(:group, path: "test", parent: group) }
let!(:deep_nested_group) { create(:group, path: "foo", parent: nested_group) }
it "updates children routes with new path" do
route.update_attributes(path: 'bar')
expect(described_class.exists?(path: 'bar')).to be_truthy
expect(described_class.exists?(path: 'bar/test')).to be_truthy
expect(described_class.exists?(path: 'bar/test/foo')).to be_truthy
end
end
end
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