Merge branch '45035-force-push-api' into 'master'

Accept force option on commit via API

Closes #45035

See merge request gitlab-org/gitlab-ce!25286
This commit is contained in:
Nick Thomas 2019-03-06 10:44:59 +00:00
commit c19c5197e1
12 changed files with 53 additions and 17 deletions

View file

@ -1 +1 @@
1.23.0 1.24.0

View file

@ -421,7 +421,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 1.12.0', require: 'gitaly' gem 'gitaly-proto', '~> 1.13.0', require: 'gitaly'
gem 'grpc', '~> 1.15.0' gem 'grpc', '~> 1.15.0'

View file

@ -279,7 +279,7 @@ GEM
gettext_i18n_rails (>= 0.7.1) gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gitaly-proto (1.12.0) gitaly-proto (1.13.0)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab-default_value_for (3.1.1) gitlab-default_value_for (3.1.1)
@ -310,7 +310,7 @@ GEM
representable (~> 3.0) representable (~> 3.0)
retriable (>= 2.0, < 4.0) retriable (>= 2.0, < 4.0)
google-protobuf (3.6.1) google-protobuf (3.6.1)
googleapis-common-protos-types (1.0.2) googleapis-common-protos-types (1.0.3)
google-protobuf (~> 3.0) google-protobuf (~> 3.0)
googleauth (0.6.6) googleauth (0.6.6)
faraday (~> 0.12) faraday (~> 0.12)
@ -1018,7 +1018,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3) gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 1.12.0) gitaly-proto (~> 1.13.0)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-default_value_for (~> 3.1.1) gitlab-default_value_for (~> 3.1.1)
gitlab-markup (~> 1.6.5) gitlab-markup (~> 1.6.5)

View file

@ -11,6 +11,7 @@ module Commits
@start_project = params[:start_project] || @project @start_project = params[:start_project] || @project
@start_branch = params[:start_branch] @start_branch = params[:start_branch]
@branch_name = params[:branch_name] @branch_name = params[:branch_name]
@force = params[:force] || false
end end
def execute def execute
@ -42,6 +43,10 @@ module Commits
@start_branch != @branch_name || @start_project != @project @start_branch != @branch_name || @start_project != @project
end end
def force?
!!@force
end
def validate! def validate!
validate_permissions! validate_permissions!
validate_on_branch! validate_on_branch!
@ -65,13 +70,13 @@ module Commits
end end
def validate_branch_existence! def validate_branch_existence!
if !project.empty_repo? && different_branch? && repository.branch_exists?(@branch_name) if !project.empty_repo? && different_branch? && repository.branch_exists?(@branch_name) && !force?
raise_error("A branch called '#{@branch_name}' already exists. Switch to that branch in order to make changes") raise_error("A branch called '#{@branch_name}' already exists. Switch to that branch in order to make changes")
end end
end end
def validate_new_branch_name! def validate_new_branch_name!
result = ValidateNewBranchService.new(project, current_user).execute(@branch_name) result = ValidateNewBranchService.new(project, current_user).execute(@branch_name, force: force?)
if result[:status] == :error if result[:status] == :error
raise_error("Something went wrong when we tried to create '#{@branch_name}' for you: #{result[:message]}") raise_error("Something went wrong when we tried to create '#{@branch_name}' for you: #{result[:message]}")

View file

@ -46,7 +46,8 @@ module Files
author_email: @author_email, author_email: @author_email,
author_name: @author_name, author_name: @author_name,
start_project: @start_project, start_project: @start_project,
start_branch_name: @start_branch start_branch_name: @start_branch,
force: force?
) )
rescue ArgumentError => e rescue ArgumentError => e
raise_error(e) raise_error(e)

View file

@ -3,14 +3,14 @@
require_relative 'base_service' require_relative 'base_service'
class ValidateNewBranchService < BaseService class ValidateNewBranchService < BaseService
def execute(branch_name) def execute(branch_name, force: false)
valid_branch = Gitlab::GitRefValidator.validate(branch_name) valid_branch = Gitlab::GitRefValidator.validate(branch_name)
unless valid_branch unless valid_branch
return error('Branch name is invalid') return error('Branch name is invalid')
end end
if project.repository.branch_exists?(branch_name) if project.repository.branch_exists?(branch_name) && !force
return error('Branch already exists') return error('Branch already exists')
end end

View file

@ -0,0 +1,5 @@
---
title: Accept force option to overwrite branch on commit via API
merge_request: 25286
author:
type: added

View file

@ -79,6 +79,7 @@ POST /projects/:id/repository/commits
| `author_email` | string | no | Specify the commit author's email address | | `author_email` | string | no | Specify the commit author's email address |
| `author_name` | string | no | Specify the commit author's name | | `author_name` | string | no | Specify the commit author's name |
| `stats` | boolean | no | Include commit stats. Default is true | | `stats` | boolean | no | Include commit stats. Default is true |
| `force` | boolean | no | When `true` overwrites the target branch with a new commit based on the `start_branch` |
| `actions[]` Attribute | Type | Required | Description | | `actions[]` Attribute | Type | Required | Description |
| --------------------- | ---- | -------- | ----------- | | --------------------- | ---- | -------- | ----------- |

View file

@ -99,6 +99,7 @@ module API
optional :author_email, type: String, desc: 'Author email for commit' optional :author_email, type: String, desc: 'Author email for commit'
optional :author_name, type: String, desc: 'Author name for commit' optional :author_name, type: String, desc: 'Author name for commit'
optional :stats, type: Boolean, default: true, desc: 'Include commit stats' optional :stats, type: Boolean, default: true, desc: 'Include commit stats'
optional :force, type: Boolean, default: false, desc: 'When `true` overwrites the target branch with a new commit based on the `start_branch`'
end end
post ':id/repository/commits' do post ':id/repository/commits' do
authorize_push_to_branch!(params[:branch]) authorize_push_to_branch!(params[:branch])

View file

@ -853,17 +853,20 @@ module Gitlab
true true
end end
# rubocop:disable Metrics/ParameterLists
def multi_action( def multi_action(
user, branch_name:, message:, actions:, user, branch_name:, message:, actions:,
author_email: nil, author_name: nil, author_email: nil, author_name: nil,
start_branch_name: nil, start_repository: self) start_branch_name: nil, start_repository: self,
force: false)
wrapped_gitaly_errors do wrapped_gitaly_errors do
gitaly_operation_client.user_commit_files(user, branch_name, gitaly_operation_client.user_commit_files(user, branch_name,
message, actions, author_email, author_name, message, actions, author_email, author_name,
start_branch_name, start_repository) start_branch_name, start_repository, force)
end end
end end
# rubocop:enable Metrics/ParameterLists
def write_config(full_path:) def write_config(full_path:)
return unless full_path.present? return unless full_path.present?

View file

@ -277,14 +277,14 @@ module Gitlab
end end
end end
# rubocop:disable Metrics/ParameterLists
def user_commit_files( def user_commit_files(
user, branch_name, commit_message, actions, author_email, author_name, user, branch_name, commit_message, actions, author_email, author_name,
start_branch_name, start_repository) start_branch_name, start_repository, force = false)
req_enum = Enumerator.new do |y| req_enum = Enumerator.new do |y|
header = user_commit_files_request_header(user, branch_name, header = user_commit_files_request_header(user, branch_name,
commit_message, actions, author_email, author_name, commit_message, actions, author_email, author_name,
start_branch_name, start_repository) start_branch_name, start_repository, force)
y.yield Gitaly::UserCommitFilesRequest.new(header: header) y.yield Gitaly::UserCommitFilesRequest.new(header: header)
@ -319,6 +319,7 @@ module Gitlab
Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update) Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update)
end end
# rubocop:enable Metrics/ParameterLists
def user_commit_patches(user, branch_name, patches) def user_commit_patches(user, branch_name, patches)
header = Gitaly::UserApplyPatchRequest::Header.new( header = Gitaly::UserApplyPatchRequest::Header.new(
@ -382,9 +383,10 @@ module Gitlab
Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update) Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update)
end end
# rubocop:disable Metrics/ParameterLists
def user_commit_files_request_header( def user_commit_files_request_header(
user, branch_name, commit_message, actions, author_email, author_name, user, branch_name, commit_message, actions, author_email, author_name,
start_branch_name, start_repository) start_branch_name, start_repository, force)
Gitaly::UserCommitFilesRequestHeader.new( Gitaly::UserCommitFilesRequestHeader.new(
repository: @gitaly_repo, repository: @gitaly_repo,
@ -394,9 +396,11 @@ module Gitlab
commit_author_name: encode_binary(author_name), commit_author_name: encode_binary(author_name),
commit_author_email: encode_binary(author_email), commit_author_email: encode_binary(author_email),
start_branch_name: encode_binary(start_branch_name), start_branch_name: encode_binary(start_branch_name),
start_repository: start_repository.gitaly_repository start_repository: start_repository.gitaly_repository,
force: force
) )
end end
# rubocop:enable Metrics/ParameterLists
def user_commit_files_action_header(action) def user_commit_files_action_header(action)
Gitaly::UserCommitFilesActionHeader.new( Gitaly::UserCommitFilesActionHeader.new(

View file

@ -235,6 +235,22 @@ describe Files::MultiService do
expect(blob).to be_present expect(blob).to be_present
end end
end end
context 'when force is set to true and branch already exists' do
let(:commit_params) do
{
commit_message: commit_message,
branch_name: 'feature',
start_branch: 'master',
actions: actions,
force: true
}
end
it 'is still a success' do
expect(subject.execute[:status]).to eq(:success)
end
end
end end
def update_file(path) def update_file(path)