Improve the Project factory to make `creator` defaults to namespace.owner

Also improves the `create_templates` transient attribute and use
`project.project_feature.update_columns` instead of
`project.project_feature.update_attributes!` since it's faster.

Signed-off-by: Rémy Coutable <remy@rymai.me>
This commit is contained in:
Rémy Coutable 2017-08-09 11:31:25 +02:00
parent b79a551ceb
commit 449a0587f6
5 changed files with 74 additions and 119 deletions

View File

@ -8,12 +8,47 @@ FactoryGirl.define do
factory :project, class: 'Project' do
sequence(:name) { |n| "project#{n}" }
path { name.downcase.gsub(/\s/, '_') }
namespace
creator
# Behaves differently to nil due to cache_has_external_issue_tracker
has_external_issue_tracker false
# Associations
namespace
creator { group ? create(:user) : namespace&.owner }
# Nest Project Feature attributes
transient do
wiki_access_level ProjectFeature::ENABLED
builds_access_level ProjectFeature::ENABLED
snippets_access_level ProjectFeature::ENABLED
issues_access_level ProjectFeature::ENABLED
merge_requests_access_level ProjectFeature::ENABLED
repository_access_level ProjectFeature::ENABLED
end
after(:create) do |project, evaluator|
# Builds and MRs can't have higher visibility level than repository access level.
builds_access_level = [evaluator.builds_access_level, evaluator.repository_access_level].min
merge_requests_access_level = [evaluator.merge_requests_access_level, evaluator.repository_access_level].min
project.project_feature.update_columns(
wiki_access_level: evaluator.wiki_access_level,
builds_access_level: builds_access_level,
snippets_access_level: evaluator.snippets_access_level,
issues_access_level: evaluator.issues_access_level,
merge_requests_access_level: merge_requests_access_level,
repository_access_level: evaluator.repository_access_level)
# Normally the class Projects::CreateService is used for creating
# projects, and this class takes care of making sure the owner and current
# user have access to the project. Our specs don't use said service class,
# thus we must manually refresh things here.
unless project.group || project.pending_delete
project.add_master(project.owner)
end
project.group&.refresh_members_authorized_projects
end
trait :public do
visibility_level Gitlab::VisibilityLevel::PUBLIC
end
@ -67,30 +102,28 @@ FactoryGirl.define do
test_repo
transient do
create_template nil
create_templates nil
end
after :create do |project, evaluator|
if evaluator.create_template
args = evaluator.create_template
project.add_user(args[:user], args[:access])
if evaluator.create_templates
templates_path = "#{evaluator.create_templates}_templates"
project.repository.create_file(
args[:user],
".gitlab/#{args[:path]}/bug.md",
project.creator,
".gitlab/#{templates_path}/bug.md",
'something valid',
message: 'test 3',
branch_name: 'master')
project.repository.create_file(
args[:user],
".gitlab/#{args[:path]}/template_test.md",
project.creator,
".gitlab/#{templates_path}/template_test.md",
'template_test',
message: 'test 1',
branch_name: 'master')
project.repository.create_file(
args[:user],
".gitlab/#{args[:path]}/feature_proposal.md",
project.creator,
".gitlab/#{templates_path}/feature_proposal.md",
'feature_proposal',
message: 'test 2',
branch_name: 'master')
@ -142,44 +175,6 @@ FactoryGirl.define do
trait(:repository_enabled) { repository_access_level ProjectFeature::ENABLED }
trait(:repository_disabled) { repository_access_level ProjectFeature::DISABLED }
trait(:repository_private) { repository_access_level ProjectFeature::PRIVATE }
# Nest Project Feature attributes
transient do
wiki_access_level ProjectFeature::ENABLED
builds_access_level ProjectFeature::ENABLED
snippets_access_level ProjectFeature::ENABLED
issues_access_level ProjectFeature::ENABLED
merge_requests_access_level ProjectFeature::ENABLED
repository_access_level ProjectFeature::ENABLED
end
after(:create) do |project, evaluator|
# Builds and MRs can't have higher visibility level than repository access level.
builds_access_level = [evaluator.builds_access_level, evaluator.repository_access_level].min
merge_requests_access_level = [evaluator.merge_requests_access_level, evaluator.repository_access_level].min
project.project_feature
.update_attributes!(
wiki_access_level: evaluator.wiki_access_level,
builds_access_level: builds_access_level,
snippets_access_level: evaluator.snippets_access_level,
issues_access_level: evaluator.issues_access_level,
merge_requests_access_level: merge_requests_access_level,
repository_access_level: evaluator.repository_access_level
)
# Normally the class Projects::CreateService is used for creating
# projects, and this class takes care of making sure the owner and current
# user have access to the project. Our specs don't use said service class,
# thus we must manually refresh things here.
owner = project.owner
if owner && owner.is_a?(User) && !project.pending_delete
project.members.create!(user: owner, access_level: Gitlab::Access::MASTER)
end
project.group&.refresh_members_authorized_projects
end
end
# Project with empty repository

View File

@ -1,5 +1,5 @@
FactoryGirl.define do
factory :user, aliases: [:author, :assignee, :recipient, :owner, :creator, :resource_owner] do
factory :user, aliases: [:author, :assignee, :recipient, :owner, :resource_owner] do
email { generate(:email) }
name { generate(:name) }
username { generate(:username) }

View File

@ -1,41 +1,28 @@
require 'spec_helper'
describe Gitlab::Template::IssueTemplate do
subject { described_class }
let(:user) { create(:user) }
let(:project) do
create(:project,
:repository,
create_template: {
user: user,
access: Gitlab::Access::MASTER,
path: 'issue_templates'
})
end
let(:project) { create(:project, :repository, create_templates: :issue) }
describe '.all' do
it 'strips the md suffix' do
expect(subject.all(project).first.name).not_to end_with('.issue_template')
expect(described_class.all(project).first.name).not_to end_with('.issue_template')
end
it 'combines the globals and rest' do
all = subject.all(project).map(&:name)
all = described_class.all(project).map(&:name)
expect(all).to include('bug')
expect(all).to include('feature_proposal')
expect(all).to include('template_test')
end
end
describe '.find' do
it 'returns nil if the file does not exist' do
expect { subject.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
expect { described_class.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
it 'returns the issue object of a valid file' do
ruby = subject.find('bug', project)
ruby = described_class.find('bug', project)
expect(ruby).to be_a described_class
expect(ruby.name).to eq('bug')
@ -44,21 +31,17 @@ describe Gitlab::Template::IssueTemplate do
describe '.by_category' do
it 'return array of templates' do
all = subject.by_category('', project).map(&:name)
all = described_class.by_category('', project).map(&:name)
expect(all).to include('bug')
expect(all).to include('feature_proposal')
expect(all).to include('template_test')
end
context 'when repo is bare or empty' do
let(:empty_project) { create(:project) }
before do
empty_project.add_user(user, Gitlab::Access::MASTER)
end
it "returns empty array" do
templates = subject.by_category('', empty_project)
templates = described_class.by_category('', empty_project)
expect(templates).to be_empty
end
end
@ -66,26 +49,23 @@ describe Gitlab::Template::IssueTemplate do
describe '#content' do
it 'loads the full file' do
issue_template = subject.new('.gitlab/issue_templates/bug.md', project)
issue_template = described_class.new('.gitlab/issue_templates/bug.md', project)
expect(issue_template.name).to eq 'bug'
expect(issue_template.content).to eq('something valid')
end
it 'raises error when file is not found' do
issue_template = subject.new('.gitlab/issue_templates/bugnot.md', project)
issue_template = described_class.new('.gitlab/issue_templates/bugnot.md', project)
expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
context "when repo is empty" do
let(:empty_project) { create(:project) }
before do
empty_project.add_user(user, Gitlab::Access::MASTER)
end
it "raises file not found" do
issue_template = subject.new('.gitlab/issue_templates/not_existent.md', empty_project)
issue_template = described_class.new('.gitlab/issue_templates/not_existent.md', empty_project)
expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
end

View File

@ -1,41 +1,28 @@
require 'spec_helper'
describe Gitlab::Template::MergeRequestTemplate do
subject { described_class }
let(:user) { create(:user) }
let(:project) do
create(:project,
:repository,
create_template: {
user: user,
access: Gitlab::Access::MASTER,
path: 'merge_request_templates'
})
end
let(:project) { create(:project, :repository, create_templates: :merge_request) }
describe '.all' do
it 'strips the md suffix' do
expect(subject.all(project).first.name).not_to end_with('.issue_template')
expect(described_class.all(project).first.name).not_to end_with('.issue_template')
end
it 'combines the globals and rest' do
all = subject.all(project).map(&:name)
all = described_class.all(project).map(&:name)
expect(all).to include('bug')
expect(all).to include('feature_proposal')
expect(all).to include('template_test')
end
end
describe '.find' do
it 'returns nil if the file does not exist' do
expect { subject.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
expect { described_class.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
it 'returns the merge request object of a valid file' do
ruby = subject.find('bug', project)
ruby = described_class.find('bug', project)
expect(ruby).to be_a described_class
expect(ruby.name).to eq('bug')
@ -44,21 +31,17 @@ describe Gitlab::Template::MergeRequestTemplate do
describe '.by_category' do
it 'return array of templates' do
all = subject.by_category('', project).map(&:name)
all = described_class.by_category('', project).map(&:name)
expect(all).to include('bug')
expect(all).to include('feature_proposal')
expect(all).to include('template_test')
end
context 'when repo is bare or empty' do
let(:empty_project) { create(:project) }
before do
empty_project.add_user(user, Gitlab::Access::MASTER)
end
it "returns empty array" do
templates = subject.by_category('', empty_project)
templates = described_class.by_category('', empty_project)
expect(templates).to be_empty
end
end
@ -66,26 +49,23 @@ describe Gitlab::Template::MergeRequestTemplate do
describe '#content' do
it 'loads the full file' do
issue_template = subject.new('.gitlab/merge_request_templates/bug.md', project)
issue_template = described_class.new('.gitlab/merge_request_templates/bug.md', project)
expect(issue_template.name).to eq 'bug'
expect(issue_template.content).to eq('something valid')
end
it 'raises error when file is not found' do
issue_template = subject.new('.gitlab/merge_request_templates/bugnot.md', project)
issue_template = described_class.new('.gitlab/merge_request_templates/bugnot.md', project)
expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
context "when repo is empty" do
let(:empty_project) { create(:project) }
before do
empty_project.add_user(user, Gitlab::Access::MASTER)
end
it "raises file not found" do
issue_template = subject.new('.gitlab/merge_request_templates/not_existent.md', empty_project)
issue_template = described_class.new('.gitlab/merge_request_templates/not_existent.md', empty_project)
expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError)
end
end

View File

@ -8,8 +8,8 @@ describe API::Projects do
let(:user2) { create(:user) }
let(:user3) { create(:user) }
let(:admin) { create(:admin) }
let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
let(:project2) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace) }
let(:project) { create(:project, namespace: user.namespace) }
let(:project2) { create(:project, path: 'project2', namespace: user.namespace) }
let(:snippet) { create(:project_snippet, :public, author: user, project: project, title: 'example') }
let(:project_member) { create(:project_member, :developer, user: user3, project: project) }
let(:user4) { create(:user) }