Adds chmod action to POST /projects/:id/repository/commits API

With this action the user can update the execute_filemode of a given file in the repository.
This commit is contained in:
Jacopo 2018-09-23 12:48:29 +02:00
parent a1529944e9
commit 271776d4aa
8 changed files with 142 additions and 19 deletions

View file

@ -1 +1 @@
0.121.0
0.122.0

View file

@ -2,7 +2,7 @@
module Files
class MultiService < Files::BaseService
UPDATE_FILE_ACTIONS = %w(update move delete).freeze
UPDATE_FILE_ACTIONS = %w(update move delete chmod).freeze
def create_commit!
transformer = Lfs::FileTransformer.new(project, @branch_name)

View file

@ -0,0 +1,5 @@
---
title: Allows to chmod file with commits API
merge_request: 21866
author: Jacopo Beschi @jacopo-beschi
type: added

View file

@ -83,12 +83,13 @@ POST /projects/:id/repository/commits
| `actions[]` Attribute | Type | Required | Description |
| --------------------- | ---- | -------- | ----------- |
| `action` | string | yes | The action to perform, `create`, `delete`, `move`, `update` |
| `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` |
| `previous_path` | string | no | Original full path to the file being moved. Ex. `lib/class1.rb` |
| `content` | string | no | File content, required for all except `delete`. Optional for `move` |
| `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` |
| `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. |
| `execute_filemode` | boolean | no | When `true/false` enables/disables the execute flag on the file. Only considered for `chmod` action. |
```bash
PAYLOAD=$(cat << 'JSON'
@ -115,6 +116,11 @@ PAYLOAD=$(cat << 'JSON'
"action": "update",
"file_path": "foo/bar5",
"content": "new content"
},
{
"action": "chmod",
"file_path": "foo/bar5",
"execute_filemode": true
}
]
}

View file

@ -73,7 +73,26 @@ module API
params do
requires :branch, type: String, desc: 'Name of the branch to commit into. To create a new branch, also provide `start_branch`.', allow_blank: false
requires :commit_message, type: String, desc: 'Commit message'
requires :actions, type: Array[Hash], desc: 'Actions to perform in commit'
requires :actions, type: Array, desc: 'Actions to perform in commit' do
requires :action, type: String, desc: 'The action to perform, `create`, `delete`, `move`, `update`, `chmod`', values: %w[create update move delete chmod].freeze
requires :file_path, type: String, desc: 'Full path to the file. Ex. `lib/class.rb`'
given action: ->(action) { action == 'move' } do
requires :previous_path, type: String, desc: 'Original full path to the file being moved. Ex. `lib/class1.rb`'
end
given action: ->(action) { %w[create move].include? action } do
optional :content, type: String, desc: 'File content'
end
given action: ->(action) { action == 'update' } do
requires :content, type: String, desc: 'File content'
end
optional :encoding, type: String, desc: '`text` or `base64`', default: 'text', values: %w[text base64]
given action: ->(action) { %w[update move delete].include? action } do
optional :last_commit_id, type: String, desc: 'Last known file commit id'
end
given action: ->(action) { action == 'chmod' } do
requires :execute_filemode, type: Boolean, desc: 'When `true/false` enables/disables the execute flag on the file.'
end
end
optional :start_branch, type: String, desc: 'Name of the branch to start the new commit from'
optional :author_email, type: String, desc: 'Author email for commit'
optional :author_name, type: String, desc: 'Author name for commit'

View file

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

View file

@ -238,7 +238,7 @@ describe API::Commits do
describe 'create' do
let(:message) { 'Created file' }
let!(:invalid_c_params) do
let(:invalid_c_params) do
{
branch: 'master',
commit_message: message,
@ -251,7 +251,7 @@ describe API::Commits do
]
}
end
let!(:valid_c_params) do
let(:valid_c_params) do
{
branch: 'master',
commit_message: message,
@ -264,7 +264,7 @@ describe API::Commits do
]
}
end
let!(:valid_utf8_c_params) do
let(:valid_utf8_c_params) do
{
branch: 'master',
commit_message: message,
@ -315,7 +315,7 @@ describe API::Commits do
describe 'delete' do
let(:message) { 'Deleted file' }
let!(:invalid_d_params) do
let(:invalid_d_params) do
{
branch: 'markdown',
commit_message: message,
@ -327,7 +327,7 @@ describe API::Commits do
]
}
end
let!(:valid_d_params) do
let(:valid_d_params) do
{
branch: 'markdown',
commit_message: message,
@ -356,7 +356,7 @@ describe API::Commits do
describe 'move' do
let(:message) { 'Moved file' }
let!(:invalid_m_params) do
let(:invalid_m_params) do
{
branch: 'feature',
commit_message: message,
@ -370,7 +370,7 @@ describe API::Commits do
]
}
end
let!(:valid_m_params) do
let(:valid_m_params) do
{
branch: 'feature',
commit_message: message,
@ -401,7 +401,7 @@ describe API::Commits do
describe 'update' do
let(:message) { 'Updated file' }
let!(:invalid_u_params) do
let(:invalid_u_params) do
{
branch: 'master',
commit_message: message,
@ -414,7 +414,7 @@ describe API::Commits do
]
}
end
let!(:valid_u_params) do
let(:valid_u_params) do
{
branch: 'master',
commit_message: message,
@ -442,9 +442,57 @@ describe API::Commits do
end
end
describe 'chmod' do
let(:message) { 'Chmod +x file' }
let(:file_path) { 'files/ruby/popen.rb' }
let(:execute_filemode) { true }
let(:params) do
{
branch: 'master',
commit_message: message,
actions: [
{
action: 'chmod',
file_path: file_path,
execute_filemode: execute_filemode
}
]
}
end
it 'responds with success' do
post api(url, user), params
expect(response).to have_gitlab_http_status(201)
expect(json_response['title']).to eq(message)
end
context 'when execute_filemode is false' do
let(:execute_filemode) { false }
it 'responds with success' do
post api(url, user), params
expect(response).to have_gitlab_http_status(201)
expect(json_response['title']).to eq(message)
end
end
context "when the file doesn't exists" do
let(:file_path) { 'foo/bar.baz' }
it "responds with 400" do
post api(url, user), params
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']).to eq("A file with this name doesn't exist")
end
end
end
describe 'multiple operations' do
let(:message) { 'Multiple actions' }
let!(:invalid_mo_params) do
let(:invalid_mo_params) do
{
branch: 'master',
commit_message: message,
@ -468,11 +516,16 @@ describe API::Commits do
action: 'update',
file_path: 'foo/bar.baz',
content: 'puts 8'
},
{
action: 'chmod',
file_path: 'files/ruby/popen.rb',
execute_filemode: true
}
]
}
end
let!(:valid_mo_params) do
let(:valid_mo_params) do
{
branch: 'master',
commit_message: message,
@ -496,6 +549,11 @@ describe API::Commits do
action: 'update',
file_path: 'files/ruby/popen.rb',
content: 'puts 8'
},
{
action: 'chmod',
file_path: 'files/ruby/popen.rb',
execute_filemode: true
}
]
}

View file

@ -11,6 +11,7 @@ describe Files::MultiService do
let(:new_file_path) { 'files/ruby/popen.rb' }
let(:file_content) { 'New content' }
let(:action) { 'update' }
let(:commit_message) { 'Update File' }
let!(:original_commit_id) do
Gitlab::Git::Commit.last_for_path(project.repository, branch_name, original_file_path).sha
@ -30,7 +31,7 @@ describe Files::MultiService do
let(:commit_params) do
{
commit_message: "Update File",
commit_message: commit_message,
branch_name: branch_name,
start_branch: branch_name,
actions: actions
@ -84,6 +85,39 @@ describe Files::MultiService do
end
end
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
context 'when moving a file' do
let(:action) { 'move' }
let(:new_file_path) { 'files/ruby/new_popen.rb' }