2019-07-31 22:56:46 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
require "spec_helper"
|
|
|
|
|
2023-05-27 22:25:52 +05:30
|
|
|
RSpec.describe Files::MultiService, feature_category: :source_code_management do
|
2018-03-17 18:26:18 +05:30
|
|
|
subject { described_class.new(project, user, commit_params) }
|
|
|
|
|
|
|
|
let(:project) { create(:project, :repository) }
|
2018-05-09 12:01:36 +05:30
|
|
|
let(:repository) { project.repository }
|
2018-03-17 18:26:18 +05:30
|
|
|
let(:user) { create(:user) }
|
|
|
|
let(:branch_name) { project.default_branch }
|
|
|
|
let(:original_file_path) { 'files/ruby/popen.rb' }
|
|
|
|
let(:new_file_path) { 'files/ruby/popen.rb' }
|
2018-05-09 12:01:36 +05:30
|
|
|
let(:file_content) { 'New content' }
|
2018-03-17 18:26:18 +05:30
|
|
|
let(:action) { 'update' }
|
2018-12-05 23:21:45 +05:30
|
|
|
let(:commit_message) { 'Update File' }
|
2018-03-17 18:26:18 +05:30
|
|
|
|
|
|
|
let!(:original_commit_id) do
|
|
|
|
Gitlab::Git::Commit.last_for_path(project.repository, branch_name, original_file_path).sha
|
|
|
|
end
|
|
|
|
|
2023-05-27 22:25:52 +05:30
|
|
|
let(:branch_commit_id) do
|
|
|
|
Gitlab::Git::Commit.find(project.repository, branch_name).sha
|
|
|
|
end
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
let(:default_action) do
|
|
|
|
{
|
|
|
|
action: action,
|
|
|
|
file_path: new_file_path,
|
|
|
|
previous_path: original_file_path,
|
|
|
|
content: file_content,
|
|
|
|
last_commit_id: original_commit_id
|
|
|
|
}
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
let(:actions) { [default_action] }
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
let(:commit_params) do
|
|
|
|
{
|
2018-12-05 23:21:45 +05:30
|
|
|
commit_message: commit_message,
|
2018-03-17 18:26:18 +05:30
|
|
|
branch_name: branch_name,
|
|
|
|
start_branch: branch_name,
|
|
|
|
actions: actions
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
2018-11-18 11:00:15 +05:30
|
|
|
project.add_maintainer(user)
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
describe '#execute' do
|
|
|
|
context 'with a valid action' do
|
|
|
|
it 'returns a hash with the :success status' do
|
|
|
|
results = subject.execute
|
|
|
|
|
|
|
|
expect(results[:status]).to eq(:success)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with an invalid action' do
|
|
|
|
let(:action) { 'rename' }
|
|
|
|
|
|
|
|
it 'returns a hash with the :error status' do
|
|
|
|
results = subject.execute
|
|
|
|
|
|
|
|
expect(results[:status]).to eq(:error)
|
|
|
|
expect(results[:message]).to match(/Unknown action/)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'Updating files' do
|
|
|
|
context 'when the file has been previously updated' do
|
|
|
|
before do
|
|
|
|
update_file(original_file_path)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'rejects the commit' do
|
|
|
|
results = subject.execute
|
|
|
|
|
|
|
|
expect(results[:status]).to eq(:error)
|
|
|
|
expect(results[:message]).to match(new_file_path)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-05-27 22:25:52 +05:30
|
|
|
context 'when file not changed, but later commit id is used' do
|
|
|
|
let(:actions) { [default_action.merge(last_commit_id: branch_commit_id)] }
|
|
|
|
|
|
|
|
it 'accepts the commit' do
|
|
|
|
results = subject.execute
|
|
|
|
|
|
|
|
expect(results[:status]).to eq(:success)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
context 'when the file have not been modified' do
|
|
|
|
it 'accepts the commit' do
|
|
|
|
results = subject.execute
|
|
|
|
|
|
|
|
expect(results[:status]).to eq(:success)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-12-05 23:21:45 +05:30
|
|
|
describe 'changing execute_filemode of a file' do
|
|
|
|
let(:commit_message) { 'Chmod +x file' }
|
|
|
|
let(:file_path) { original_file_path }
|
|
|
|
let(:default_action) do
|
|
|
|
{
|
|
|
|
action: 'chmod',
|
|
|
|
file_path: file_path,
|
|
|
|
execute_filemode: true
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'accepts the commit' do
|
|
|
|
results = subject.execute
|
|
|
|
|
|
|
|
expect(results[:status]).to eq(:success)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'updates the execute_filemode of the file' do
|
|
|
|
expect { subject.execute }.to change { repository.blob_at_branch(branch_name, file_path).mode }.from('100644').to('100755')
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when the file doesn't exists" do
|
|
|
|
let(:file_path) { 'files/wrong_path.rb' }
|
|
|
|
|
|
|
|
it 'rejects the commit' do
|
|
|
|
results = subject.execute
|
|
|
|
|
|
|
|
expect(results[:status]).to eq(:error)
|
|
|
|
expect(results[:message]).to eq("A file with this name doesn't exist")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
context 'when moving a file' do
|
|
|
|
let(:action) { 'move' }
|
|
|
|
let(:new_file_path) { 'files/ruby/new_popen.rb' }
|
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
let(:result) { subject.execute }
|
|
|
|
let(:blob) { repository.blob_at_branch(branch_name, new_file_path) }
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
context 'when original file has been updated' do
|
|
|
|
before do
|
|
|
|
update_file(original_file_path)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'rejects the commit' do
|
2019-02-15 15:39:39 +05:30
|
|
|
expect(result[:status]).to eq(:error)
|
|
|
|
expect(result[:message]).to match(original_file_path)
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
context 'when original file has not been updated' do
|
2018-03-17 18:26:18 +05:30
|
|
|
it 'moves the file' do
|
2019-02-15 15:39:39 +05:30
|
|
|
expect(result[:status]).to eq(:success)
|
2019-01-03 12:48:30 +05:30
|
|
|
expect(blob).to be_present
|
2019-02-15 15:39:39 +05:30
|
|
|
expect(blob.data).to eq(file_content)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when content is nil' do
|
|
|
|
let(:file_content) { nil }
|
|
|
|
|
|
|
|
it 'moves the existing content untouched' do
|
|
|
|
original_content = repository.blob_at_branch(branch_name, original_file_path).data
|
|
|
|
|
|
|
|
expect(result[:status]).to eq(:success)
|
|
|
|
expect(blob).to be_present
|
|
|
|
expect(blob.data).to eq(original_content)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when content is an empty string' do
|
|
|
|
let(:file_content) { '' }
|
|
|
|
|
|
|
|
it 'moves the file and empties it' do
|
|
|
|
expect(result[:status]).to eq(:success)
|
|
|
|
expect(blob).not_to be_nil
|
|
|
|
expect(blob.data).to eq('')
|
|
|
|
end
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
context 'when creating a file matching an LFS filter' do
|
|
|
|
let(:action) { 'create' }
|
|
|
|
let(:branch_name) { 'lfs' }
|
|
|
|
let(:new_file_path) { 'test_file.lfs' }
|
|
|
|
|
|
|
|
before do
|
|
|
|
allow(project).to receive(:lfs_enabled?).and_return(true)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates an LFS pointer' do
|
|
|
|
subject.execute
|
|
|
|
|
|
|
|
blob = repository.blob_at('lfs', new_file_path)
|
|
|
|
|
|
|
|
expect(blob.data).to start_with(Gitlab::Git::LfsPointerFile::VERSION_LINE)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates an LfsObject with the file's content" do
|
|
|
|
subject.execute
|
|
|
|
|
|
|
|
expect(LfsObject.last.file.read).to eq file_content
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with base64 encoded content' do
|
|
|
|
let(:raw_file_content) { 'Raw content' }
|
|
|
|
let(:file_content) { Base64.encode64(raw_file_content) }
|
|
|
|
let(:actions) { [default_action.merge(encoding: 'base64')] }
|
|
|
|
|
|
|
|
it 'creates an LFS pointer' do
|
|
|
|
subject.execute
|
|
|
|
|
|
|
|
blob = repository.blob_at('lfs', new_file_path)
|
|
|
|
|
|
|
|
expect(blob.data).to start_with(Gitlab::Git::LfsPointerFile::VERSION_LINE)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates an LfsObject with the file's content" do
|
|
|
|
subject.execute
|
|
|
|
|
|
|
|
expect(LfsObject.last.file.read).to eq raw_file_content
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'links the LfsObject to the project' do
|
|
|
|
expect do
|
|
|
|
subject.execute
|
|
|
|
end.to change { project.lfs_objects.count }.by(1)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-03-17 18:26:18 +05:30
|
|
|
context 'when file status validation is skipped' do
|
|
|
|
let(:action) { 'create' }
|
|
|
|
let(:new_file_path) { 'files/ruby/new_file.rb' }
|
|
|
|
|
|
|
|
it 'does not check the last commit' do
|
|
|
|
expect(Gitlab::Git::Commit).not_to receive(:last_for_path)
|
|
|
|
|
|
|
|
subject.execute
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'creates the file' do
|
|
|
|
subject.execute
|
|
|
|
|
|
|
|
blob = project.repository.blob_at_branch(branch_name, new_file_path)
|
|
|
|
|
|
|
|
expect(blob).to be_present
|
|
|
|
end
|
|
|
|
end
|
2019-07-07 11:18:12 +05:30
|
|
|
|
|
|
|
context 'when force is set to true and branch already exists' do
|
|
|
|
let(:commit_params) do
|
|
|
|
{
|
|
|
|
commit_message: commit_message,
|
|
|
|
branch_name: 'feature',
|
|
|
|
start_branch: 'master',
|
|
|
|
actions: actions,
|
|
|
|
force: true
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'is still a success' do
|
|
|
|
expect(subject.execute[:status]).to eq(:success)
|
|
|
|
end
|
|
|
|
end
|
2018-03-17 18:26:18 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def update_file(path)
|
|
|
|
params = {
|
|
|
|
file_path: path,
|
|
|
|
start_branch: branch_name,
|
|
|
|
branch_name: branch_name,
|
|
|
|
commit_message: 'Update file',
|
|
|
|
file_content: 'New content'
|
|
|
|
}
|
|
|
|
|
|
|
|
Files::UpdateService.new(project, user, params).execute
|
|
|
|
end
|
|
|
|
end
|