diff --git a/CHANGELOG b/CHANGELOG index aa9f93274ec..a5d26db7626 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ v 8.11.0 (unreleased) v 8.10.0 (unreleased) - Fix profile activity heatmap to show correct day name (eanplatter) - Expose {should,force}_remove_source_branch (Ben Boeckel) + - Add the functionality to be able to rename a file. !5049 (tiagonbotelho) - Disable PostgreSQL statement timeout during migrations - Fix projects dropdown loading performance with a simplified api cal. !5113 (tiagonbotelho) - Fix commit builds API, return all builds for all pipelines for given commit. !4849 diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb index dacb5679dd3..f2b8f297bc2 100644 --- a/app/controllers/concerns/creates_commit.rb +++ b/app/controllers/concerns/creates_commit.rb @@ -7,7 +7,8 @@ module CreatesCommit commit_params = @commit_params.merge( source_project: @project, source_branch: @ref, - target_branch: @target_branch + target_branch: @target_branch, + previous_path: @previous_path ) result = service.new(@tree_edit_project, current_user, commit_params).execute diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index 5356fdf010d..eda3727a28d 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -38,6 +38,12 @@ class Projects::BlobController < Projects::ApplicationController end def update + if params[:file_path].present? + @previous_path = @path + @path = params[:file_path] + @commit_params[:file_path] = @path + end + after_edit_path = if from_merge_request && @target_branch == @ref diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) + diff --git a/app/models/repository.rb b/app/models/repository.rb index c187bad39ad..1a2ac90da51 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -733,6 +733,33 @@ class Repository end end + def update_file(user, path, content, branch:, previous_path:, message:) + commit_with_hooks(user, branch) do |ref| + committer = user_to_committer(user) + options = {} + options[:committer] = committer + options[:author] = committer + options[:commit] = { + message: message, + branch: ref, + update_ref: false + } + + options[:file] = { + content: content, + path: path, + update: true + } + + if previous_path + options[:file][:previous_path] = previous_path + Gitlab::Git::Blob.rename(raw_repository, options) + else + Gitlab::Git::Blob.commit(raw_repository, options) + end + end + end + def remove_file(user, path, message, branch) commit_with_hooks(user, branch) do |ref| committer = user_to_committer(user) diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index 55da949f56a..c4a206f785e 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -9,12 +9,14 @@ module Files @commit_message = params[:commit_message] @file_path = params[:file_path] + @previous_path = params[:previous_path] @file_content = if params[:file_content_encoding] == 'base64' Base64.decode64(params[:file_content]) else params[:file_content] end + # Validate parameters validate # Create new branch if it different from source_branch diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index 1960dc7d949..8d2b5083179 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -3,7 +3,10 @@ require_relative "base_service" module Files class UpdateService < Files::BaseService def commit - repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch, true) + repository.update_file(current_user, @file_path, @file_content, + branch: @target_branch, + previous_path: @previous_path, + message: @commit_message) end end end diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml index 29c7d45074a..ff379bafb26 100644 --- a/app/views/projects/blob/_editor.html.haml +++ b/app/views/projects/blob/_editor.html.haml @@ -4,7 +4,9 @@ = icon('code-fork') = ref %span.editor-file-name - = @path + - if current_action?(:edit) || current_action?(:update) + = text_field_tag 'file_path', (params[:file_path] || @path), + class: 'form-control new-file-path' - if current_action?(:new) || current_action?(:create) %span.editor-file-name diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index e14cec589fe..110df6bbd22 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -130,6 +130,36 @@ describe Repository, models: true do end end + describe :commit_file do + it 'commits change to a file successfully' do + expect do + repository.commit_file(user, 'CHANGELOG', 'Changelog!', + 'Updates file content', + 'master', true) + end.to change { repository.commits('master').count }.by(1) + + blob = repository.blob_at('master', 'CHANGELOG') + + expect(blob.data).to eq('Changelog!') + end + end + + describe :update_file do + it 'updates filename successfully' do + expect do + repository.update_file(user, 'NEWLICENSE', 'Copyright!', + branch: 'master', + previous_path: 'LICENSE', + message: 'Changes filename') + end.to change { repository.commits('master').count }.by(1) + + files = repository.ls_files('master') + + expect(files).not_to include('LICENSE') + expect(files).to include('NEWLICENSE') + end + end + describe "search_files" do let(:results) { repository.search_files('feature', 'master') } subject { results }