Commit f2375df8 authored by Peter Leitzen's avatar Peter Leitzen

Merge branch 'vij-snippet-create-update-errors' into 'master'

Handle snippet file path errors in services

See merge request gitlab-org/gitlab!31333
parents b9a8d445 23639b80
...@@ -65,11 +65,12 @@ module SnippetsActions ...@@ -65,11 +65,12 @@ module SnippetsActions
params[:line_ending] == 'raw' ? content : content.gsub(/\r\n/, "\n") params[:line_ending] == 'raw' ? content : content.gsub(/\r\n/, "\n")
end end
def check_repository_error def handle_repository_error(action)
repository_errors = Array(snippet.errors.delete(:repository)) errors = Array(snippet.errors.delete(:repository))
flash.now[:alert] = repository_errors.first if repository_errors.present? flash.now[:alert] = errors.first if errors.present?
recaptcha_check_with_fallback(repository_errors.empty?) { render :edit }
recaptcha_check_with_fallback(errors.empty?) { render action }
end end
def redirect_if_binary def redirect_if_binary
......
...@@ -52,15 +52,8 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -52,15 +52,8 @@ class Projects::SnippetsController < Projects::ApplicationController
create_params = snippet_params.merge(spammable_params) create_params = snippet_params.merge(spammable_params)
service_response = Snippets::CreateService.new(project, current_user, create_params).execute service_response = Snippets::CreateService.new(project, current_user, create_params).execute
@snippet = service_response.payload[:snippet] @snippet = service_response.payload[:snippet]
repository_operation_error = service_response.error? && !@snippet.persisted? && @snippet.valid?
if repository_operation_error handle_repository_error(:new)
flash.now[:alert] = service_response.message
render :new
else
recaptcha_check_with_fallback { render :new }
end
end end
def update def update
...@@ -69,7 +62,7 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -69,7 +62,7 @@ class Projects::SnippetsController < Projects::ApplicationController
service_response = Snippets::UpdateService.new(project, current_user, update_params).execute(@snippet) service_response = Snippets::UpdateService.new(project, current_user, update_params).execute(@snippet)
@snippet = service_response.payload[:snippet] @snippet = service_response.payload[:snippet]
check_repository_error handle_repository_error(:edit)
end end
def show def show
......
...@@ -52,12 +52,9 @@ class SnippetsController < ApplicationController ...@@ -52,12 +52,9 @@ class SnippetsController < ApplicationController
create_params = snippet_params.merge(spammable_params) create_params = snippet_params.merge(spammable_params)
service_response = Snippets::CreateService.new(nil, current_user, create_params).execute service_response = Snippets::CreateService.new(nil, current_user, create_params).execute
@snippet = service_response.payload[:snippet] @snippet = service_response.payload[:snippet]
repository_operation_error = service_response.error? && !@snippet.persisted? && @snippet.valid?
if repository_operation_error if service_response.error? && @snippet.errors[:repository].present?
flash.now[:alert] = service_response.message handle_repository_error(:new)
render :new
else else
move_temporary_files if @snippet.valid? && params[:files] move_temporary_files if @snippet.valid? && params[:files]
...@@ -71,7 +68,7 @@ class SnippetsController < ApplicationController ...@@ -71,7 +68,7 @@ class SnippetsController < ApplicationController
service_response = Snippets::UpdateService.new(nil, current_user, update_params).execute(@snippet) service_response = Snippets::UpdateService.new(nil, current_user, update_params).execute(@snippet)
@snippet = service_response.payload[:snippet] @snippet = service_response.payload[:snippet]
check_repository_error handle_repository_error(:edit)
end end
def show def show
......
...@@ -44,6 +44,9 @@ class SnippetRepository < ApplicationRecord ...@@ -44,6 +44,9 @@ class SnippetRepository < ApplicationRecord
Gitlab::Git::PreReceiveError, Gitlab::Git::PreReceiveError,
Gitlab::Git::CommandError, Gitlab::Git::CommandError,
ArgumentError => error ArgumentError => error
logger.error(message: "Snippet git error. Reason: #{error.message}", snippet: snippet.id)
raise commit_error_exception(error) raise commit_error_exception(error)
end end
...@@ -91,7 +94,7 @@ class SnippetRepository < ApplicationRecord ...@@ -91,7 +94,7 @@ class SnippetRepository < ApplicationRecord
def commit_error_exception(err) def commit_error_exception(err)
if invalid_path_error?(err) if invalid_path_error?(err)
InvalidPathError.new('Invalid Path') # To avoid returning the message with the path included InvalidPathError.new('Invalid file name') # To avoid returning the message with the path included
elsif invalid_signature_error?(err) elsif invalid_signature_error?(err)
InvalidSignatureError.new(err.message) InvalidSignatureError.new(err.message)
else else
......
...@@ -11,5 +11,22 @@ module Snippets ...@@ -11,5 +11,22 @@ module Snippets
payload: { snippet: snippet } payload: { snippet: snippet }
) )
end end
def add_snippet_repository_error(snippet:, error:)
message = repository_error_message(error)
snippet.errors.add(:repository, message)
end
def repository_error_message(error)
message = self.is_a?(Snippets::CreateService) ? _("Error creating the snippet") : _("Error updating the snippet")
# We only want to include additional error detail in the message
# if the error is not a CommitError because we cannot guarantee the message
# will be user-friendly
message += " - #{error.message}" unless error.instance_of?(SnippetRepository::CommitError)
message
end
end end
end end
...@@ -60,7 +60,7 @@ module Snippets ...@@ -60,7 +60,7 @@ module Snippets
@snippet = @snippet.dup @snippet = @snippet.dup
end end
@snippet.errors.add(:base, e.message) add_snippet_repository_error(snippet: @snippet, error: e)
false false
end end
......
...@@ -54,7 +54,8 @@ module Snippets ...@@ -54,7 +54,8 @@ module Snippets
snippet.save snippet.save
end end
snippet.errors.add(:repository, 'Error updating the snippet') add_snippet_repository_error(snippet: snippet, error: e)
log_error(e.message) log_error(e.message)
# If the commit action failed we remove it because # If the commit action failed we remove it because
......
---
title: Modify Snippet git path errors to be more helpful
merge_request: 31333
author:
type: changed
...@@ -8459,6 +8459,9 @@ msgstr "" ...@@ -8459,6 +8459,9 @@ msgstr ""
msgid "Error creating new iteration" msgid "Error creating new iteration"
msgstr "" msgstr ""
msgid "Error creating the snippet"
msgstr ""
msgid "Error deleting %{issuableType}" msgid "Error deleting %{issuableType}"
msgstr "" msgstr ""
...@@ -8579,6 +8582,9 @@ msgstr "" ...@@ -8579,6 +8582,9 @@ msgstr ""
msgid "Error updating status of to-do item." msgid "Error updating status of to-do item."
msgstr "" msgstr ""
msgid "Error updating the snippet"
msgstr ""
msgid "Error uploading file" msgid "Error uploading file"
msgstr "" msgstr ""
......
...@@ -99,7 +99,7 @@ shared_examples_for 'snippet editor' do ...@@ -99,7 +99,7 @@ shared_examples_for 'snippet editor' do
end end
context 'when the git operation fails' do context 'when the git operation fails' do
let(:error) { 'This is a git error' } let(:error) { 'Error creating the snippet' }
before do before do
allow_next_instance_of(Snippets::CreateService) do |instance| allow_next_instance_of(Snippets::CreateService) do |instance|
......
...@@ -42,7 +42,7 @@ describe 'Projects > Snippets > User updates a snippet', :js do ...@@ -42,7 +42,7 @@ describe 'Projects > Snippets > User updates a snippet', :js do
context 'when the git operation fails' do context 'when the git operation fails' do
before do before do
allow_next_instance_of(Snippets::UpdateService) do |instance| allow_next_instance_of(Snippets::UpdateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError) allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
end end
fill_in('project_snippet_title', with: 'Snippet new title') fill_in('project_snippet_title', with: 'Snippet new title')
...@@ -52,7 +52,7 @@ describe 'Projects > Snippets > User updates a snippet', :js do ...@@ -52,7 +52,7 @@ describe 'Projects > Snippets > User updates a snippet', :js do
end end
it 'renders edit page and displays the error' do it 'renders edit page and displays the error' do
expect(page.find('.flash-container span').text).to eq('Error updating the snippet') expect(page.find('.flash-container span').text).to eq('Error updating the snippet - Error Message')
expect(page).to have_content('Edit Snippet') expect(page).to have_content('Edit Snippet')
end end
end end
......
...@@ -79,7 +79,7 @@ shared_examples_for 'snippet editor' do ...@@ -79,7 +79,7 @@ shared_examples_for 'snippet editor' do
end end
context 'when the git operation fails' do context 'when the git operation fails' do
let(:error) { 'This is a git error' } let(:error) { 'Error creating the snippet' }
before do before do
allow_next_instance_of(Snippets::CreateService) do |instance| allow_next_instance_of(Snippets::CreateService) do |instance|
......
...@@ -73,7 +73,7 @@ describe 'User edits snippet', :js do ...@@ -73,7 +73,7 @@ describe 'User edits snippet', :js do
context 'when the git operation fails' do context 'when the git operation fails' do
before do before do
allow_next_instance_of(Snippets::UpdateService) do |instance| allow_next_instance_of(Snippets::UpdateService) do |instance|
allow(instance).to receive(:create_commit).and_raise(StandardError) allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message')
end end
fill_in 'personal_snippet_title', with: 'New Snippet Title' fill_in 'personal_snippet_title', with: 'New Snippet Title'
...@@ -83,7 +83,7 @@ describe 'User edits snippet', :js do ...@@ -83,7 +83,7 @@ describe 'User edits snippet', :js do
end end
it 'renders edit page and displays the error' do it 'renders edit page and displays the error' do
expect(page.find('.flash-container span').text).to eq('Error updating the snippet') expect(page.find('.flash-container span').text).to eq('Error updating the snippet - Error Message')
expect(page).to have_content('Edit Snippet') expect(page).to have_content('Edit Snippet')
end end
end end
......
...@@ -169,8 +169,8 @@ describe Snippets::CreateService do ...@@ -169,8 +169,8 @@ describe Snippets::CreateService do
expect { subject }.not_to change { Snippet.count } expect { subject }.not_to change { Snippet.count }
end end
it 'returns the error' do it 'returns a generic creation error' do
expect(snippet.errors.full_messages).to include('Repository could not be created') expect(snippet.errors[:repository]).to eq ['Error creating the snippet - Repository could not be created']
end end
it 'does not return a snippet with an id' do it 'does not return a snippet with an id' do
...@@ -178,6 +178,14 @@ describe Snippets::CreateService do ...@@ -178,6 +178,14 @@ describe Snippets::CreateService do
end end
end end
context 'when repository creation fails with invalid file name' do
let(:extra_opts) { { file_name: 'invalid://file/name/here' } }
it 'returns an appropriate error' do
expect(snippet.errors[:repository]).to eq ['Error creating the snippet - Invalid file name']
end
end
context 'when the commit action fails' do context 'when the commit action fails' do
before do before do
allow_next_instance_of(SnippetRepository) do |instance| allow_next_instance_of(SnippetRepository) do |instance|
...@@ -209,11 +217,11 @@ describe Snippets::CreateService do ...@@ -209,11 +217,11 @@ describe Snippets::CreateService do
subject subject
end end
it 'returns the error' do it 'returns a generic error' do
response = subject response = subject
expect(response).to be_error expect(response).to be_error
expect(response.payload[:snippet].errors.full_messages).to eq ['foobar'] expect(response.payload[:snippet].errors[:repository]).to eq ['Error creating the snippet']
end end
end end
......
...@@ -121,7 +121,7 @@ describe Snippets::UpdateService do ...@@ -121,7 +121,7 @@ describe Snippets::UpdateService do
response = subject response = subject
expect(response).to be_error expect(response).to be_error
expect(response.payload[:snippet].errors[:repository].to_sentence).to eq 'Error updating the snippet' expect(response.payload[:snippet].errors[:repository].to_sentence).to eq 'Error updating the snippet - Repository could not be created'
end end
it 'does not try to commit file' do it 'does not try to commit file' do
......
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