BigW Consortium Gitlab

teamcity_service.rb 4.23 KB
Newer Older
Dmitriy Zaporozhets committed
1 2 3 4
# == Schema Information
#
# Table name: services
#
5 6 7 8 9 10 11 12 13
#  id                    :integer          not null, primary key
#  type                  :string(255)
#  title                 :string(255)
#  project_id            :integer
#  created_at            :datetime
#  updated_at            :datetime
#  active                :boolean          default(FALSE), not null
#  properties            :text
#  template              :boolean          default(FALSE)
14 15 16 17
#  push_events           :boolean          default(TRUE)
#  issues_events         :boolean          default(TRUE)
#  merge_requests_events :boolean          default(TRUE)
#  tag_push_events       :boolean          default(TRUE)
18
#  note_events           :boolean          default(TRUE), not null
Stan Hu committed
19
#  build_events          :boolean          default(FALSE), not null
Dmitriy Zaporozhets committed
20 21
#

22 23 24 25 26
class TeamcityService < CiService
  include HTTParty

  prop_accessor :teamcity_url, :build_type, :username, :password

27
  validates :teamcity_url, presence: true, url: true, if: :activated?
28
  validates :build_type, presence: true, if: :activated?
29 30
  validates :username,
    presence: true,
31
    if: ->(service) { service.activated? && service.password }
32 33
  validates :password,
    presence: true,
34
    if: ->(service) { service.activated? && service.username }
35 36 37 38

  attr_accessor :response

  after_save :compose_service_hook, if: :activated?
39
  before_update :reset_password
40 41 42 43 44 45

  def compose_service_hook
    hook = service_hook || build_service_hook
    hook.save
  end

46
  def reset_password
47
    if teamcity_url_changed? && !password_touched?
48 49 50 51
      self.password = nil
    end
  end

52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
  def title
    'JetBrains TeamCity CI'
  end

  def description
    'A continuous integration and build server'
  end

  def help
    'The build configuration in Teamcity must use the build format '\
    'number %build.vcs.number% '\
    'you will also want to configure monitoring of all branches so merge '\
    'requests build, that setting is in the vsc root advanced settings.'
  end

  def to_param
    'teamcity'
  end

71 72 73 74
  def supported_events
    %w(push)
  end

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
  def fields
    [
      { type: 'text', name: 'teamcity_url',
        placeholder: 'TeamCity root URL like https://teamcity.example.com' },
      { type: 'text', name: 'build_type',
        placeholder: 'Build configuration ID' },
      { type: 'text', name: 'username',
        placeholder: 'A user with permissions to trigger a manual build' },
      { type: 'password', name: 'password' },
    ]
  end

  def build_info(sha)
    url = URI.parse("#{teamcity_url}/httpAuth/app/rest/builds/"\
                    "branch:unspecified:any,number:#{sha}")
    auth = {
      username: username,
      password: password,
    }
    @response = HTTParty.get("#{url}", verify: false, basic_auth: auth)
  end

Valery Sizov committed
97
  def build_page(sha, ref)
98 99 100 101 102 103 104 105 106 107 108 109 110 111
    build_info(sha) if @response.nil? || !@response.code

    if @response.code != 200
      # If actual build link can't be determined,
      # send user to build summary page.
      "#{teamcity_url}/viewLog.html?buildTypeId=#{build_type}"
    else
      # If actual build link is available, go to build result page.
      built_id = @response['build']['id']
      "#{teamcity_url}/viewLog.html?buildId=#{built_id}"\
      "&buildTypeId=#{build_type}"
    end
  end

Valery Sizov committed
112
  def commit_status(sha, ref)
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    build_info(sha) if @response.nil? || !@response.code
    return :error unless @response.code == 200 || @response.code == 404

    status = if @response.code == 404
               'Pending'
             else
               @response['build']['status']
             end

    if status.include?('SUCCESS')
      'success'
    elsif status.include?('FAILURE')
      'failed'
    elsif status.include?('Pending')
      'pending'
    else
      :error
    end
  end

133
  def execute(data)
134
    return unless supported_events.include?(data[:object_kind])
135

136 137 138 139 140
    auth = {
      username: username,
      password: password,
    }

141
    branch = Gitlab::Git.ref_name(data[:ref])
142 143 144 145 146 147 148

    self.class.post("#{teamcity_url}/httpAuth/app/rest/buildQueue",
                    body: "<build branchName=\"#{branch}\">"\
                          "<buildType id=\"#{build_type}\"/>"\
                          '</build>',
                    headers: { 'Content-type' => 'application/xml' },
                    basic_auth: auth
149
                   )
150 151
  end
end