Commit c8cf26b8 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'vij-add-files-to-snippet-create-endpoint' into 'master'

Add support for files in PersonalSnippet REST API

See merge request gitlab-org/gitlab!38281
parents e5dd1ae7 b2d90477
...@@ -10,6 +10,23 @@ module API ...@@ -10,6 +10,23 @@ module API
requires :ref, type: String, desc: 'The name of branch, tag or commit' requires :ref, type: String, desc: 'The name of branch, tag or commit'
end end
params :create_file_params do
optional :files, type: Array, desc: 'An array of files' do
requires :file_path, type: String, file_path: true, allow_blank: false, desc: 'The path of a snippet file'
requires :content, type: String, allow_blank: false, desc: 'The content of a snippet file'
end
optional :content, type: String, allow_blank: false, desc: 'The content of a snippet'
given :content do
requires :file_name, type: String, desc: 'The name of a snippet file'
end
mutually_exclusive :files, :content
exactly_one_of :files, :content
end
def content_for(snippet) def content_for(snippet)
if snippet.empty_repo? if snippet.empty_repo?
env['api.format'] = :txt env['api.format'] = :txt
...@@ -35,5 +52,12 @@ module API ...@@ -35,5 +52,12 @@ module API
send_git_blob(repo, blob) send_git_blob(repo, blob)
end end
end end
def process_file_args(args)
args[:snippet_actions] = args.delete(:files)&.map do |file|
file[:action] = :create
file.symbolize_keys
end
end
end end
end end
...@@ -66,18 +66,23 @@ module API ...@@ -66,18 +66,23 @@ module API
end end
params do params do
requires :title, type: String, allow_blank: false, desc: 'The title of a snippet' requires :title, type: String, allow_blank: false, desc: 'The title of a snippet'
requires :file_name, type: String, desc: 'The name of a snippet file'
requires :content, type: String, allow_blank: false, desc: 'The content of a snippet'
optional :description, type: String, desc: 'The description of a snippet' optional :description, type: String, desc: 'The description of a snippet'
optional :visibility, type: String, optional :visibility, type: String,
values: Gitlab::VisibilityLevel.string_values, values: Gitlab::VisibilityLevel.string_values,
default: 'internal', default: 'internal',
desc: 'The visibility of the snippet' desc: 'The visibility of the snippet'
use :create_file_params
end end
post do post do
authorize! :create_snippet authorize! :create_snippet
attrs = declared_params(include_missing: false).merge(request: request, api: true) attrs = declared_params(include_missing: false).tap do |create_args|
create_args[:request] = request
create_args[:api] = true
process_file_args(create_args)
end
service_response = ::Snippets::CreateService.new(nil, current_user, attrs).execute service_response = ::Snippets::CreateService.new(nil, current_user, attrs).execute
snippet = service_response.payload[:snippet] snippet = service_response.payload[:snippet]
......
...@@ -229,13 +229,15 @@ RSpec.describe API::Snippets do ...@@ -229,13 +229,15 @@ RSpec.describe API::Snippets do
let(:base_params) do let(:base_params) do
{ {
title: 'Test Title', title: 'Test Title',
file_name: 'test.rb',
description: 'test description', description: 'test description',
content: 'puts "hello world"',
visibility: 'public' visibility: 'public'
} }
end end
let(:params) { base_params.merge(extra_params) } let(:file_path) { 'file_1.rb' }
let(:file_content) { 'puts "hello world"' }
let(:params) { base_params.merge(file_params, extra_params) }
let(:file_params) { { files: [{ file_path: file_path, content: file_content }] } }
let(:extra_params) { {} } let(:extra_params) { {} }
subject { post api("/snippets/", user), params: params } subject { post api("/snippets/", user), params: params }
...@@ -251,7 +253,7 @@ RSpec.describe API::Snippets do ...@@ -251,7 +253,7 @@ RSpec.describe API::Snippets do
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(json_response['title']).to eq(params[:title]) expect(json_response['title']).to eq(params[:title])
expect(json_response['description']).to eq(params[:description]) expect(json_response['description']).to eq(params[:description])
expect(json_response['file_name']).to eq(params[:file_name]) expect(json_response['file_name']).to eq(file_path)
expect(json_response['files']).to eq(snippet.blobs.map { |blob| snippet_blob_file(blob) }) expect(json_response['files']).to eq(snippet.blobs.map { |blob| snippet_blob_file(blob) })
expect(json_response['visibility']).to eq(params[:visibility]) expect(json_response['visibility']).to eq(params[:visibility])
end end
...@@ -265,9 +267,90 @@ RSpec.describe API::Snippets do ...@@ -265,9 +267,90 @@ RSpec.describe API::Snippets do
it 'commit the files to the repository' do it 'commit the files to the repository' do
subject subject
blob = snippet.repository.blob_at('master', params[:file_name]) blob = snippet.repository.blob_at('master', file_path)
expect(blob.data).to eq params[:content] expect(blob.data).to eq file_content
end
end
context 'with files parameter' do
using RSpec::Parameterized::TableSyntax
where(:path, :content, :status, :error) do
'.gitattributes' | 'file content' | :created | nil
'valid/path/file.rb' | 'file content' | :created | nil
'.gitattributes' | nil | :bad_request | 'files[0][content] is empty'
'.gitattributes' | '' | :bad_request | 'files[0][content] is empty'
'' | 'file content' | :bad_request | 'files[0][file_path] is empty'
nil | 'file content' | :bad_request | 'files[0][file_path] should be a valid file path, files[0][file_path] is empty'
'../../etc/passwd' | 'file content' | :bad_request | 'files[0][file_path] should be a valid file path'
end
with_them do
let(:file_path) { path }
let(:file_content) { content }
before do
subject
end
it 'responds correctly' do
expect(response).to have_gitlab_http_status(status)
expect(json_response['error']).to eq(error)
end
end
it 'returns 400 if both files and content are provided' do
params[:file_name] = 'foo.rb'
params[:content] = 'bar'
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'files, content are mutually exclusive'
end
it 'returns 400 when neither files or content are provided' do
params.delete(:files)
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'files, content are missing, exactly one parameter must be provided'
end
context 'with multiple files' do
let(:file_params) do
{
files: [
{ file_path: 'file_1.rb', content: 'puts "hello world"' },
{ file_path: 'file_2.rb', content: 'puts "hello world 2"' }
]
}
end
it_behaves_like 'snippet creation'
end
end
context 'without files parameter' do
let(:file_params) { { file_name: 'testing.rb', content: 'snippet content' } }
it 'allows file_name and content parameters' do
subject
expect(response).to have_gitlab_http_status(:created)
end
it 'returns 400 if file_name and content are not both provided' do
params.delete(:file_name)
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'file_name is missing'
end end
end end
...@@ -305,15 +388,6 @@ RSpec.describe API::Snippets do ...@@ -305,15 +388,6 @@ RSpec.describe API::Snippets do
expect(response).to have_gitlab_http_status(:bad_request) expect(response).to have_gitlab_http_status(:bad_request)
end end
it 'returns 400 if content is blank' do
params[:content] = ''
subject
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq 'content is empty'
end
it 'returns 400 if title is blank' do it 'returns 400 if title is blank' do
params[:title] = '' params[:title] = ''
......
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