Read about our upcoming Code of Conduct on this issue

bamboo_service.rb 3.95 KB
Newer Older
1
2
# frozen_string_literal: true

Drew Blessing's avatar
Drew Blessing committed
3
class BambooService < CiService
4
5
  include ReactiveService

Drew Blessing's avatar
Drew Blessing committed
6
7
  prop_accessor :bamboo_url, :build_key, :username, :password

8
  validates :bamboo_url, presence: true, public_url: true, if: :activated?
Drew Blessing's avatar
Drew Blessing committed
9
  validates :build_key, presence: true, if: :activated?
10
11
  validates :username,
    presence: true,
Gabriel Mazetto's avatar
Gabriel Mazetto committed
12
    if: ->(service) { service.activated? && service.password }
13
14
  validates :password,
    presence: true,
Gabriel Mazetto's avatar
Gabriel Mazetto committed
15
    if: ->(service) { service.activated? && service.username }
Drew Blessing's avatar
Drew Blessing committed
16
17
18
19

  attr_accessor :response

  after_save :compose_service_hook, if: :activated?
20
  before_update :reset_password
Drew Blessing's avatar
Drew Blessing committed
21
22
23
24
25
26

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

27
  def reset_password
28
    if bamboo_url_changed? && !password_touched?
29
30
31
32
      self.password = nil
    end
  end

Drew Blessing's avatar
Drew Blessing committed
33
  def title
34
    s_('BambooService|Atlassian Bamboo CI')
Drew Blessing's avatar
Drew Blessing committed
35
36
37
  end

  def description
38
    s_('BambooService|A continuous integration and build server')
Drew Blessing's avatar
Drew Blessing committed
39
40
41
  end

  def help
42
    s_('BambooService|You must set up automatic revision labeling and a repository trigger in Bamboo.')
Drew Blessing's avatar
Drew Blessing committed
43
44
  end

45
  def self.to_param
Drew Blessing's avatar
Drew Blessing committed
46
47
48
49
50
51
    'bamboo'
  end

  def fields
    [
        { type: 'text', name: 'bamboo_url',
52
          placeholder: s_('BambooService|Bamboo root URL like https://bamboo.example.com'), required: true },
Drew Blessing's avatar
Drew Blessing committed
53
        { type: 'text', name: 'build_key',
54
          placeholder: s_('BambooService|Bamboo build plan key like KEY'), required: true },
Drew Blessing's avatar
Drew Blessing committed
55
        { type: 'text', name: 'username',
56
          placeholder: s_('BambooService|A user with API access, if applicable') },
57
        { type: 'password', name: 'password' }
Drew Blessing's avatar
Drew Blessing committed
58
59
60
    ]
  end

61
62
  def build_page(sha, ref)
    with_reactive_cache(sha, ref) {|cached| cached[:build_page] }
Drew Blessing's avatar
Drew Blessing committed
63
64
  end

65
66
67
  def commit_status(sha, ref)
    with_reactive_cache(sha, ref) {|cached| cached[:commit_status] }
  end
Drew Blessing's avatar
Drew Blessing committed
68

69
70
71
  def execute(data)
    return unless supported_events.include?(data[:object_kind])

72
    get_path("updateAndBuild.action", { buildKey: build_key })
73
74
75
  end

  def calculate_reactive_cache(sha, ref)
76
    response = get_path("rest/api/latest/result/byChangeset/#{sha}")
77
78
79
80
81
82

    { build_page: read_build_page(response), commit_status: read_commit_status(response) }
  end

  private

83
84
85
86
87
88
89
90
91
92
  def get_build_result(response)
    return if response.code != 200

    # May be nil if no result, a single result hash, or an array if multiple results for a given changeset.
    result = response.dig('results', 'results', 'result')

    # In case of multiple results, arbitrarily assume the last one is the most relevant.
    return result.last if result.is_a?(Array)

    result
93
94
  end

95
  def read_build_page(response)
96
    result = get_build_result(response)
97
    key =
98
      if result.blank?
99
100
101
102
        # If actual build link can't be determined, send user to build summary page.
        build_key
      else
        # If actual build link is available, go to build result page.
103
        result.dig('planResultKey', 'key')
104
105
106
      end

    build_url("browse/#{key}")
Drew Blessing's avatar
Drew Blessing committed
107
108
  end

109
110
  def read_commit_status(response)
    return :error unless response.code == 200 || response.code == 404
Drew Blessing's avatar
Drew Blessing committed
111

112
113
114
115
116
117
118
119
120
    result = get_build_result(response)
    status =
      if result.blank?
        'Pending'
      else
        result.dig('buildState')
      end

    return :error unless status.present?
Drew Blessing's avatar
Drew Blessing committed
121
122
123
124
125
126
127
128
129
130
131
132

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

133
  def build_url(path)
134
    Gitlab::Utils.append_path(bamboo_url, path)
135
136
  end

137
  def get_path(path, query_params = {})
138
    url = build_url(path)
139
140

    if username.blank? && password.blank?
141
      Gitlab::HTTP.get(url, verify: false, query: query_params)
142
    else
143
144
145
146
147
148
149
150
      query_params[:os_authType] = 'basic'
      Gitlab::HTTP.get(url,
                       verify: false,
                       query: query_params,
                       basic_auth: {
                         username: username,
                         password: password
                       })
151
    end
Drew Blessing's avatar
Drew Blessing committed
152
153
  end
end