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:
commit
c19c5197e1
12 changed files with 53 additions and 17 deletions
|
@ -1 +1 @@
|
||||||
1.23.0
|
1.24.0
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -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'
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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]}")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
5
changelogs/unreleased/45035-force-push-api.yml
Normal file
5
changelogs/unreleased/45035-force-push-api.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Accept force option to overwrite branch on commit via API
|
||||||
|
merge_request: 25286
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -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 |
|
||||||
| --------------------- | ---- | -------- | ----------- |
|
| --------------------- | ---- | -------- | ----------- |
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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?
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue