summaryrefslogtreecommitdiff
path: root/app/services/files
diff options
context:
space:
mode:
authorMarc Siegfriedt <marc@techaccelerator.com>2016-08-29 23:58:32 +0000
committerMarc Siegfriedt <marc@techaccelerator.com>2016-10-05 17:42:52 +0000
commita1ee8cf5ad07256807f15590bdb5f56152d55553 (patch)
tree9f90bc8f0d3c5d65e9b8778bc9d80e4ecd8855dd /app/services/files
parent4bc27cd17b304abce01fad1fce56fce32a4ee099 (diff)
downloadgitlab-ce-a1ee8cf5ad07256807f15590bdb5f56152d55553.tar.gz
multi-file commit
add docs and tests - add additional validation allow move without content updated response
Diffstat (limited to 'app/services/files')
-rw-r--r--app/services/files/base_service.rb11
-rw-r--r--app/services/files/multi_service.rb124
-rw-r--r--app/services/files/update_service.rb6
3 files changed, 133 insertions, 8 deletions
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index e8465729d06..9bd4bd464f7 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -27,8 +27,9 @@ module Files
create_target_branch
end
- if commit
- success
+ result = commit
+ if result
+ success(result: result)
else
error('Something went wrong. Your changes were not committed')
end
@@ -42,6 +43,12 @@ module Files
@source_branch != @target_branch || @source_project != @project
end
+ def file_has_changed?
+ return false unless @last_commit_sha && last_commit
+
+ @last_commit_sha != last_commit.sha
+ end
+
def raise_error(message)
raise ValidationError.new(message)
end
diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb
new file mode 100644
index 00000000000..d28912e1301
--- /dev/null
+++ b/app/services/files/multi_service.rb
@@ -0,0 +1,124 @@
+require_relative "base_service"
+
+module Files
+ class MultiService < Files::BaseService
+ class FileChangedError < StandardError; end
+
+ def commit
+ repository.multi_action(
+ user: current_user,
+ branch: @target_branch,
+ message: @commit_message,
+ actions: params[:actions],
+ author_email: @author_email,
+ author_name: @author_name
+ )
+ end
+
+ private
+
+ def validate
+ super
+
+ params[:actions].each_with_index do |action, index|
+ unless action[:file_path].present?
+ raise_error("You must specify a file_path.")
+ end
+
+ regex_check(action[:file_path])
+ regex_check(action[:previous_path]) if action[:previous_path]
+
+ if project.empty_repo? && action[:action] != :create
+ raise_error("No files to #{action[:action]}.")
+ end
+
+ validate_file_exists(action)
+
+ case action[:action]
+ when :create
+ validate_create(action)
+ when :update
+ validate_update(action)
+ when :delete
+ validate_delete(action)
+ when :move
+ validate_move(action, index)
+ else
+ raise_error("Unknown action type `#{action[:action]}`.")
+ end
+ end
+ end
+
+ def validate_file_exists(action)
+ return if action[:action] == :create
+
+ file_path = action[:file_path]
+ file_path = action[:previous_path] if action[:action] == :move
+
+ blob = repository.blob_at_branch(params[:branch_name], file_path)
+
+ unless blob
+ raise_error("File to be #{action[:action]}d `#{file_path}` does not exist.")
+ end
+ end
+
+ def last_commit
+ Gitlab::Git::Commit.last_for_path(repository, @source_branch, @file_path)
+ end
+
+ def regex_check(file)
+ if file =~ Gitlab::Regex.directory_traversal_regex
+ raise_error(
+ 'Your changes could not be committed, because the file name, `' +
+ file +
+ '` ' +
+ Gitlab::Regex.directory_traversal_regex_message
+ )
+ end
+
+ unless file =~ Gitlab::Regex.file_path_regex
+ raise_error(
+ 'Your changes could not be committed, because the file name, `' +
+ file +
+ '` ' +
+ Gitlab::Regex.file_path_regex_message
+ )
+ end
+ end
+
+ def validate_create(action)
+ return if project.empty_repo?
+
+ if repository.blob_at_branch(params[:branch_name], action[:file_path])
+ raise_error("Your changes could not be committed because a file with the name `#{action[:file_path]}` already exists.")
+ end
+ end
+
+ def validate_delete(action)
+ end
+
+ def validate_move(action, index)
+ if action[:previous_path].nil?
+ raise_error("You must supply the original file path when moving file `#{action[:file_path]}`.")
+ end
+
+ blob = repository.blob_at_branch(params[:branch_name], action[:file_path])
+
+ if blob
+ raise_error("Move destination `#{action[:file_path]}` already exists.")
+ end
+
+ if action[:content].nil?
+ blob = repository.blob_at_branch(params[:branch_name], action[:previous_path])
+ blob.load_all_data!(repository) if blob.truncated?
+ params[:actions][index][:content] = blob.data
+ end
+ end
+
+ def validate_update(action)
+ if file_has_changed?
+ raise FileChangedError.new("You are attempting to update a file `#{action[:file_path]}` that has changed since you started editing it.")
+ end
+ end
+ end
+end
diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb
index 9e9b5b63f26..c17fdb8d1f1 100644
--- a/app/services/files/update_service.rb
+++ b/app/services/files/update_service.rb
@@ -23,12 +23,6 @@ module Files
end
end
- def file_has_changed?
- return false unless @last_commit_sha && last_commit
-
- @last_commit_sha != last_commit.sha
- end
-
def last_commit
@last_commit ||= Gitlab::Git::Commit.
last_for_path(@source_project.repository, @source_branch, @file_path)