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:
Nikolay Novikov 2018-08-02 17:33:26 +00:00 committed by Fabio Pitino
parent 671d7cdc44
commit 5f1038c888
4 changed files with 158 additions and 24 deletions

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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)