Commit 31cb8d08 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents e26c47fa 3ad645a2
# frozen_string_literal: true
# This concern is used by registerd services such as TeamCityService and
# DroneCiService and add methods to perform validations on the received
# data.
module ServicePushDataValidations
extend ActiveSupport::Concern
def merge_request_valid?(data)
data.dig(:object_attributes, :state) == 'opened' && merge_request_unchecked?(data)
end
def push_valid?(data)
data[:total_commits_count] > 0 &&
!branch_removed?(data) &&
# prefer merge request trigger over push to avoid double builds
!opened_merge_requests?(data)
end
def tag_push_valid?(data)
data[:total_commits_count] > 0 && !branch_removed?(data)
end
private
def branch_removed?(data)
Gitlab::Git.blank_ref?(data[:after])
end
def opened_merge_requests?(data)
project.merge_requests
.opened
.from_project(project)
.from_source_branches(Gitlab::Git.ref_name(data[:ref]))
.exists?
end
def merge_request_unchecked?(data)
MergeRequest.state_machines[:merge_status]
.check_state?(data.dig(:object_attributes, :merge_status))
end
end
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
class DroneCiService < CiService class DroneCiService < CiService
include ReactiveService include ReactiveService
include ServicePushDataValidations
prop_accessor :drone_url, :token prop_accessor :drone_url, :token
boolean_accessor :enable_ssl_verification boolean_accessor :enable_ssl_verification
...@@ -96,23 +97,4 @@ class DroneCiService < CiService ...@@ -96,23 +97,4 @@ class DroneCiService < CiService
{ type: 'checkbox', name: 'enable_ssl_verification', title: "Enable SSL verification" } { type: 'checkbox', name: 'enable_ssl_verification', title: "Enable SSL verification" }
] ]
end end
private
def tag_push_valid?(data)
data[:total_commits_count] > 0 && !Gitlab::Git.blank_ref?(data[:after])
end
def push_valid?(data)
opened_merge_requests = project.merge_requests.opened.where(source_project_id: project.id,
source_branch: Gitlab::Git.ref_name(data[:ref]))
opened_merge_requests.empty? && data[:total_commits_count] > 0 &&
!Gitlab::Git.blank_ref?(data[:after])
end
def merge_request_valid?(data)
data[:object_attributes][:state] == 'opened' &&
MergeRequest.state_machines[:merge_status].check_state?(data[:object_attributes][:merge_status])
end
end end
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
class TeamcityService < CiService class TeamcityService < CiService
include ReactiveService include ReactiveService
include ServicePushDataValidations
prop_accessor :teamcity_url, :build_type, :username, :password prop_accessor :teamcity_url, :build_type, :username, :password
...@@ -19,6 +20,25 @@ class TeamcityService < CiService ...@@ -19,6 +20,25 @@ class TeamcityService < CiService
after_save :compose_service_hook, if: :activated? after_save :compose_service_hook, if: :activated?
before_update :reset_password 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 def compose_service_hook
hook = service_hook || build_service_hook hook = service_hook || build_service_hook
hook.save hook.save
...@@ -43,10 +63,6 @@ class TeamcityService < CiService ...@@ -43,10 +63,6 @@ class TeamcityService < CiService
'requests build, that setting is in the vsc root advanced settings.' 'requests build, that setting is in the vsc root advanced settings.'
end end
def self.to_param
'teamcity'
end
def fields def fields
[ [
{ type: 'text', name: 'teamcity_url', { type: 'text', name: 'teamcity_url',
...@@ -74,26 +90,25 @@ class TeamcityService < CiService ...@@ -74,26 +90,25 @@ class TeamcityService < CiService
end end
def execute(data) def execute(data)
return unless supported_events.include?(data[:object_kind]) case data[:object_kind]
when 'push'
execute_push(data)
when 'merge_request'
execute_merge_request(data)
end
end
auth = { private
username: username,
password: password
}
def execute_push(data)
branch = Gitlab::Git.ref_name(data[:ref]) branch = Gitlab::Git.ref_name(data[:ref])
post_to_build_queue(data, branch) if push_valid?(data)
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
)
end end
private def execute_merge_request(data)
branch = data[:object_attributes][:source_branch]
post_to_build_queue(data, branch) if merge_request_valid?(data)
end
def read_build_page(response) def read_build_page(response)
if response.code != 200 if response.code != 200
...@@ -134,10 +149,21 @@ class TeamcityService < CiService ...@@ -134,10 +149,21 @@ class TeamcityService < CiService
end end
def get_path(path) def get_path(path)
Gitlab::HTTP.get(build_url(path), verify: false, Gitlab::HTTP.get(build_url(path), verify: false, basic_auth: basic_auth)
basic_auth: { end
username: username,
password: password 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 end
end end
---
title: Protect TeamCity builds from triggering when a branch has been deleted. And a MR-option
merge_request: 29836
author: Nikolay Novikov, Raphael Tweitmann
type: fixed
...@@ -482,7 +482,7 @@ Below you can find supported syntax reference: ...@@ -482,7 +482,7 @@ Below you can find supported syntax reference:
> Example: `$VARIABLE == "some value"` > Example: `$VARIABLE == "some value"`
> Example: `$VARIABLE != "some value"` _(added in 11.11)_ > Example: `$VARIABLE != "some value"` (introduced in GitLab 11.11)
You can use equality operator `==` or `!=` to compare a variable content to a You can use equality operator `==` or `!=` to compare a variable content to a
string. We support both, double quotes and single quotes to define a string string. We support both, double quotes and single quotes to define a string
...@@ -493,7 +493,7 @@ Below you can find supported syntax reference: ...@@ -493,7 +493,7 @@ Below you can find supported syntax reference:
> Example: `$VARIABLE == null` > Example: `$VARIABLE == null`
> Example: `$VARIABLE != null` _(added in 11.11)_ > Example: `$VARIABLE != null` (introduced in GitLab 11.11)
It sometimes happens that you want to check whether a variable is defined It sometimes happens that you want to check whether a variable is defined
or not. To do that, you can compare a variable to `null` keyword, like or not. To do that, you can compare a variable to `null` keyword, like
...@@ -504,7 +504,7 @@ Below you can find supported syntax reference: ...@@ -504,7 +504,7 @@ Below you can find supported syntax reference:
> Example: `$VARIABLE == ""` > Example: `$VARIABLE == ""`
> Example: `$VARIABLE != ""` _(added in 11.11)_ > Example: `$VARIABLE != ""` (introduced in GitLab 11.11)
If you want to check whether a variable is defined, but is empty, you can If you want to check whether a variable is defined, but is empty, you can
simply compare it against an empty string, like `$VAR == ''` or non-empty simply compare it against an empty string, like `$VAR == ''` or non-empty
...@@ -514,7 +514,7 @@ Below you can find supported syntax reference: ...@@ -514,7 +514,7 @@ Below you can find supported syntax reference:
> Example: `$VARIABLE_1 == $VARIABLE_2` > Example: `$VARIABLE_1 == $VARIABLE_2`
> Example: `$VARIABLE_1 != $VARIABLE_2` _(added in 11.11)_ > Example: `$VARIABLE_1 != $VARIABLE_2` (introduced in GitLab 11.11)
It is possible to compare two variables. This is going to compare values It is possible to compare two variables. This is going to compare values
of these variables. of these variables.
...@@ -530,11 +530,11 @@ Below you can find supported syntax reference: ...@@ -530,11 +530,11 @@ Below you can find supported syntax reference:
`$STAGING` value needs to a string, with length higher than zero. `$STAGING` value needs to a string, with length higher than zero.
Variable that contains only whitespace characters is not an empty variable. Variable that contains only whitespace characters is not an empty variable.
1. Pattern matching _(added in 11.0)_ 1. Pattern matching (introduced in GitLab 11.0)
> Example: `$VARIABLE =~ /^content.*/` > Example: `$VARIABLE =~ /^content.*/`
> Example: `$VARIABLE_1 !~ /^content.*/` _(added in 11.11)_ > Example: `$VARIABLE_1 !~ /^content.*/` (introduced in GitLab 11.11)
It is possible perform pattern matching against a variable and regular It is possible perform pattern matching against a variable and regular
expression. Expression like this evaluates to truth if matches are found expression. Expression like this evaluates to truth if matches are found
...@@ -543,7 +543,7 @@ Below you can find supported syntax reference: ...@@ -543,7 +543,7 @@ Below you can find supported syntax reference:
Pattern matching is case-sensitive by default. Use `i` flag modifier, like Pattern matching is case-sensitive by default. Use `i` flag modifier, like
`/pattern/i` to make a pattern case-insensitive. `/pattern/i` to make a pattern case-insensitive.
1. Conjunction / Disjunction 1. Conjunction / Disjunction ([introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27925) in GitLab 12.0)
> Example: `$VARIABLE1 =~ /^content.*/ && $VARIABLE2 == "something"` > Example: `$VARIABLE1 =~ /^content.*/ && $VARIABLE2 == "something"`
......
...@@ -15,6 +15,8 @@ describe 'User activates JetBrains TeamCity CI' do ...@@ -15,6 +15,8 @@ describe 'User activates JetBrains TeamCity CI' do
it 'activates service' do it 'activates service' do
check('Active') check('Active')
check('Push')
check('Merge request')
fill_in('Teamcity url', with: 'http://teamcity.example.com') fill_in('Teamcity url', with: 'http://teamcity.example.com')
fill_in('Build type', with: 'GitlabTest_Build') fill_in('Build type', with: 'GitlabTest_Build')
fill_in('Username', with: 'user') fill_in('Username', with: 'user')
......
...@@ -7,10 +7,11 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do ...@@ -7,10 +7,11 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do
include StubRequests include StubRequests
let(:teamcity_url) { 'http://gitlab.com/teamcity' } let(:teamcity_url) { 'http://gitlab.com/teamcity' }
let(:project) { create(:project) }
subject(:service) do subject(:service) do
described_class.create( described_class.create(
project: create(:project), project: project,
properties: { properties: {
teamcity_url: teamcity_url, teamcity_url: teamcity_url,
username: 'mic', username: 'mic',
...@@ -207,6 +208,97 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do ...@@ -207,6 +208,97 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do
end end
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] = Gitlab::Git::BLANK_SHA
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
it 'returns nil when a merge request is opened for the same ref' do
create(:merge_request, source_project: project, source_branch: 'dev-123_branch')
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 unless merge request is marked as unchecked' do
data[:object_attributes][:merge_status] = 'can_be_merged'
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') 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' teamcity_full_url = 'http://gitlab.com/teamcity/httpAuth/app/rest/builds/branch:unspecified:any,revision:123'
auth = %w(mic password) auth = %w(mic password)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment