Skip TeamCity on branch delete and add MR trigger
This is a take over from a community contribution: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20990 Skip TeamCity push event when related to branch delete Support merge request events for TeamCity service. Add checkbox for merge request triggers in the TeamCity configuration page.
This commit is contained in:
parent
671d7cdc44
commit
5f1038c888
4 changed files with 158 additions and 24 deletions
|
@ -19,6 +19,25 @@ class TeamcityService < CiService
|
|||
after_save :compose_service_hook, if: :activated?
|
||||
before_update :reset_password
|
||||
|
||||
class << self
|
||||
def to_param
|
||||
'teamcity'
|
||||
end
|
||||
|
||||
def supported_events
|
||||
%w(push merge_request)
|
||||
end
|
||||
|
||||
def event_description(event)
|
||||
case event
|
||||
when 'push', 'push_events'
|
||||
'TeamCity CI will be triggered after every push to the repository except branch delete'
|
||||
when 'merge_request', 'merge_request_events'
|
||||
'TeamCity CI will be triggered after a merge request has been created or updated'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def compose_service_hook
|
||||
hook = service_hook || build_service_hook
|
||||
hook.save
|
||||
|
@ -43,10 +62,6 @@ class TeamcityService < CiService
|
|||
'requests build, that setting is in the vsc root advanced settings.'
|
||||
end
|
||||
|
||||
def self.to_param
|
||||
'teamcity'
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'text', name: 'teamcity_url',
|
||||
|
@ -76,21 +91,14 @@ class TeamcityService < CiService
|
|||
def execute(data)
|
||||
return unless supported_events.include?(data[:object_kind])
|
||||
|
||||
auth = {
|
||||
username: username,
|
||||
password: password
|
||||
}
|
||||
|
||||
branch = Gitlab::Git.ref_name(data[:ref])
|
||||
|
||||
Gitlab::HTTP.post(
|
||||
build_url('httpAuth/app/rest/buildQueue'),
|
||||
body: "<build branchName=\"#{branch}\">"\
|
||||
"<buildType id=\"#{build_type}\"/>"\
|
||||
'</build>',
|
||||
headers: { 'Content-type' => 'application/xml' },
|
||||
basic_auth: auth
|
||||
)
|
||||
case data[:object_kind]
|
||||
when 'push'
|
||||
branch = Gitlab::Git.ref_name(data[:ref])
|
||||
post_to_build_queue(data, branch) if push_valid?(data)
|
||||
when 'merge_request'
|
||||
branch = data[:object_attributes][:source_branch]
|
||||
post_to_build_queue(data, branch) if merge_request_valid?(data)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -134,10 +142,44 @@ class TeamcityService < CiService
|
|||
end
|
||||
|
||||
def get_path(path)
|
||||
Gitlab::HTTP.get(build_url(path), verify: false,
|
||||
basic_auth: {
|
||||
username: username,
|
||||
password: password
|
||||
})
|
||||
Gitlab::HTTP.get(build_url(path), verify: false, basic_auth: basic_auth)
|
||||
end
|
||||
|
||||
def post_to_build_queue(data, branch)
|
||||
Gitlab::HTTP.post(
|
||||
build_url('httpAuth/app/rest/buildQueue'),
|
||||
body: "<build branchName=#{branch.encode(xml: :attr)}>"\
|
||||
"<buildType id=#{build_type.encode(xml: :attr)}/>"\
|
||||
'</build>',
|
||||
headers: { 'Content-type' => 'application/xml' },
|
||||
basic_auth: basic_auth
|
||||
)
|
||||
end
|
||||
|
||||
def basic_auth
|
||||
{ username: username, password: password }
|
||||
end
|
||||
|
||||
def push_valid?(data)
|
||||
data[:total_commits_count] > 0 &&
|
||||
!branch_removed?(data) &&
|
||||
no_open_merge_requests?(data)
|
||||
end
|
||||
|
||||
def merge_request_valid?(data)
|
||||
data.dig(:object_attributes, :state) == 'opened' &&
|
||||
MergeRequest.state_machines[:merge_status].check_state?(data.dig(:object_attributes, :merge_status))
|
||||
end
|
||||
|
||||
def branch_removed?(data)
|
||||
Gitlab::Git.blank_ref?(data[:after])
|
||||
end
|
||||
|
||||
def no_open_merge_requests?(data)
|
||||
!project.merge_requests
|
||||
.opened
|
||||
.from_project(project)
|
||||
.from_source_branches(Gitlab::Git.ref_name(data[:ref]))
|
||||
.exists?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Protect TeamCity builds from triggering when a branch has been deleted. And a MR-option
|
||||
merge_request: 29836
|
||||
author: Nikolay Novikov
|
||||
type: fixed
|
|
@ -15,6 +15,8 @@ describe 'User activates JetBrains TeamCity CI' do
|
|||
|
||||
it 'activates service' do
|
||||
check('Active')
|
||||
check('Push')
|
||||
check('Merge request')
|
||||
fill_in('Teamcity url', with: 'http://teamcity.example.com')
|
||||
fill_in('Build type', with: 'GitlabTest_Build')
|
||||
fill_in('Username', with: 'user')
|
||||
|
|
|
@ -207,6 +207,91 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when push' do
|
||||
let(:data) do
|
||||
{
|
||||
object_kind: 'push',
|
||||
ref: 'refs/heads/dev-123_branch',
|
||||
after: '0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e',
|
||||
total_commits_count: 1
|
||||
}
|
||||
end
|
||||
|
||||
it 'handles push request correctly' do
|
||||
stub_post_to_build_queue(branch: 'dev-123_branch')
|
||||
|
||||
expect(service.execute(data)).to include('Ok')
|
||||
end
|
||||
|
||||
it 'returns nil when ref is blank' do
|
||||
data[:after] = "0000000000000000000000000000000000000000"
|
||||
|
||||
expect(service.execute(data)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil when there is no content' do
|
||||
data[:total_commits_count] = 0
|
||||
|
||||
expect(service.execute(data)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when merge_request' do
|
||||
let(:data) do
|
||||
{
|
||||
object_kind: 'merge_request',
|
||||
ref: 'refs/heads/dev-123_branch',
|
||||
after: '0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e',
|
||||
total_commits_count: 1,
|
||||
object_attributes: {
|
||||
state: 'opened',
|
||||
source_branch: 'dev-123_branch',
|
||||
merge_status: 'unchecked'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'handles merge request correctly' do
|
||||
stub_post_to_build_queue(branch: 'dev-123_branch')
|
||||
|
||||
expect(service.execute(data)).to include('Ok')
|
||||
end
|
||||
|
||||
it 'returns nil when merge request is not opened' do
|
||||
data[:object_attributes][:state] = 'closed'
|
||||
|
||||
expect(service.execute(data)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns nil when merge request is not unchecked or cannot_be_merged_recheck' do
|
||||
data[:object_attributes][:merge_status] = 'checked'
|
||||
|
||||
expect(service.execute(data)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns nil when event is not supported' do
|
||||
data = { object_kind: 'foo' }
|
||||
|
||||
expect(service.execute(data)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
def stub_post_to_build_queue(branch:)
|
||||
teamcity_full_url = 'http://gitlab.com/teamcity/httpAuth/app/rest/buildQueue'
|
||||
body ||= %Q(<build branchName=\"#{branch}\"><buildType id=\"foo\"/></build>)
|
||||
auth = %w(mic password)
|
||||
|
||||
stub_full_request(teamcity_full_url, method: :post).with(
|
||||
basic_auth: auth,
|
||||
body: body,
|
||||
headers: {
|
||||
'Content-Type' => 'application/xml'
|
||||
}
|
||||
).to_return(status: 200, body: 'Ok', headers: {})
|
||||
end
|
||||
|
||||
def stub_request(status: 200, body: nil, build_status: 'success')
|
||||
teamcity_full_url = 'http://gitlab.com/teamcity/httpAuth/app/rest/builds/branch:unspecified:any,revision:123'
|
||||
auth = %w(mic password)
|
||||
|
|
Loading…
Reference in a new issue