Merge branch '51083-fix-move-api' into 'master'

Commits API: Preserve file content in move operations if unspecified

Closes #52974 et #51083

See merge request gitlab-org/gitlab-ce!23387
This commit is contained in:
Rémy Coutable 2018-11-29 11:36:16 +00:00
commit 7c0718cd79
9 changed files with 55 additions and 17 deletions

View File

@ -1 +1 @@
1.1.0 1.2.0

View File

@ -432,7 +432,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 1.1.0', require: 'gitaly' gem 'gitaly-proto', '~> 1.2.0', require: 'gitaly'
gem 'grpc', '~> 1.15.0' gem 'grpc', '~> 1.15.0'
gem 'google-protobuf', '~> 3.6' gem 'google-protobuf', '~> 3.6'

View File

@ -273,7 +273,7 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gitaly-proto (1.1.0) gitaly-proto (1.2.0)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab-default_value_for (3.1.1) gitlab-default_value_for (3.1.1)
@ -1006,7 +1006,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 1.1.0) gitaly-proto (~> 1.2.0)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-default_value_for (~> 3.1.1) gitlab-default_value_for (~> 3.1.1)
gitlab-markup (~> 1.6.5) gitlab-markup (~> 1.6.5)

View File

@ -272,7 +272,7 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gitaly-proto (1.1.0) gitaly-proto (1.2.0)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab-markup (1.6.5) gitlab-markup (1.6.5)
@ -998,7 +998,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 1.1.0) gitaly-proto (~> 1.2.0)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-markup (~> 1.6.5) gitlab-markup (~> 1.6.5)
gitlab-sidekiq-fetcher gitlab-sidekiq-fetcher

View File

@ -8,6 +8,7 @@ module Files
transformer = Lfs::FileTransformer.new(project, @branch_name) transformer = Lfs::FileTransformer.new(project, @branch_name)
actions = actions_after_lfs_transformation(transformer, params[:actions]) actions = actions_after_lfs_transformation(transformer, params[:actions])
actions = transform_move_actions(actions)
commit_actions!(actions) commit_actions!(actions)
end end
@ -26,6 +27,16 @@ module Files
end end
end end
# When moving a file, `content: nil` means "use the contents of the previous
# file", while `content: ''` means "move the file and set it to empty"
def transform_move_actions(actions)
actions.map do |action|
action[:infer_content] = true if action[:content].nil?
action
end
end
def commit_actions!(actions) def commit_actions!(actions)
repository.multi_action( repository.multi_action(
current_user, current_user,

View File

@ -0,0 +1,5 @@
---
title: 'Commits API: Preserve file content in move operations if unspecified'
merge_request: 23387
author:
type: fixed

View File

@ -87,7 +87,7 @@ POST /projects/:id/repository/commits
| `action` | string | yes | The action to perform, `create`, `delete`, `move`, `update`, `chmod`| | `action` | string | yes | The action to perform, `create`, `delete`, `move`, `update`, `chmod`|
| `file_path` | string | yes | Full path to the file. Ex. `lib/class.rb` | | `file_path` | string | yes | Full path to the file. Ex. `lib/class.rb` |
| `previous_path` | string | no | Original full path to the file being moved. Ex. `lib/class1.rb`. Only considered for `move` action. | | `previous_path` | string | no | Original full path to the file being moved. Ex. `lib/class1.rb`. Only considered for `move` action. |
| `content` | string | no | File content, required for all except `delete` and `chmod`. Optional for `move` | | `content` | string | no | File content, required for all except `delete`, `chmod`, and `move`. Move actions that do not specify `content` will preserve the existing file content, and any other value of `content` will overwrite the file content. |
| `encoding` | string | no | `text` or `base64`. `text` is default. | | `encoding` | string | no | `text` or `base64`. `text` is default. |
| `last_commit_id` | string | no | Last known file commit id. Will be only considered in update, move and delete actions. | | `last_commit_id` | string | no | Last known file commit id. Will be only considered in update, move and delete actions. |
| `execute_filemode` | boolean | no | When `true/false` enables/disables the execute flag on the file. Only considered for `chmod` action. | | `execute_filemode` | boolean | no | When `true/false` enables/disables the execute flag on the file. Only considered for `chmod` action. |

View File

@ -385,7 +385,8 @@ module Gitlab
file_path: encode_binary(action[:file_path]), file_path: encode_binary(action[:file_path]),
previous_path: encode_binary(action[:previous_path]), previous_path: encode_binary(action[:previous_path]),
base64_content: action[:encoding] == 'base64', base64_content: action[:encoding] == 'base64',
execute_filemode: !!action[:execute_filemode] execute_filemode: !!action[:execute_filemode],
infer_content: !!action[:infer_content]
) )
rescue RangeError rescue RangeError
raise ArgumentError, "Unknown action '#{action[:action]}'" raise ArgumentError, "Unknown action '#{action[:action]}'"

View File

@ -122,26 +122,47 @@ describe Files::MultiService do
let(:action) { 'move' } let(:action) { 'move' }
let(:new_file_path) { 'files/ruby/new_popen.rb' } let(:new_file_path) { 'files/ruby/new_popen.rb' }
let(:result) { subject.execute }
let(:blob) { repository.blob_at_branch(branch_name, new_file_path) }
context 'when original file has been updated' do context 'when original file has been updated' do
before do before do
update_file(original_file_path) update_file(original_file_path)
end end
it 'rejects the commit' do it 'rejects the commit' do
results = subject.execute expect(result[:status]).to eq(:error)
expect(result[:message]).to match(original_file_path)
expect(results[:status]).to eq(:error)
expect(results[:message]).to match(original_file_path)
end end
end end
context 'when original file have not been updated' do context 'when original file has not been updated' do
it 'moves the file' do it 'moves the file' do
results = subject.execute expect(result[:status]).to eq(:success)
blob = project.repository.blob_at_branch(branch_name, new_file_path)
expect(results[:status]).to eq(:success)
expect(blob).to be_present expect(blob).to be_present
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
end end
end end
end end