summaryrefslogtreecommitdiff
path: root/app/models/integrations/drone_ci.rb
blob: 73f78bec38165bb0b6f17c044f1ed6ac0c50b5b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# frozen_string_literal: true

module Integrations
  class DroneCi < BaseCi
    include HasWebHook
    include PushDataValidations
    include ReactivelyCached
    prepend EnableSslVerification
    extend Gitlab::Utils::Override

    DRONE_SAAS_HOSTNAME = 'cloud.drone.io'

    prop_accessor :drone_url, :token

    validates :drone_url, presence: true, public_url: true, if: :activated?
    validates :token, presence: true, if: :activated?

    def execute(data)
      return unless project

      case data[:object_kind]
      when 'push'
        execute_web_hook!(data) if push_valid?(data)
      when 'merge_request'
        execute_web_hook!(data) if merge_request_valid?(data)
      when 'tag_push'
        execute_web_hook!(data) if tag_push_valid?(data)
      end
    end

    def allow_target_ci?
      true
    end

    def self.supported_events
      %w(push merge_request tag_push)
    end

    def commit_status_path(sha, ref)
      Gitlab::Utils.append_path(
        drone_url,
        "gitlab/#{project.full_path}/commits/#{sha}?branch=#{Addressable::URI.encode_component(ref.to_s)}&access_token=#{token}")
    end

    def commit_status(sha, ref)
      with_reactive_cache(sha, ref) { |cached| cached[:commit_status] }
    end

    def calculate_reactive_cache(sha, ref)
      response = Gitlab::HTTP.try_get(
        commit_status_path(sha, ref),
        verify: enable_ssl_verification,
        extra_log_info: { project_id: project_id },
        use_read_total_timeout: true
      )

      status =
        if response && response.code == 200 && response['status']
          case response['status']
          when 'killed'
            :canceled
          when 'failure', 'error'
            # Because drone return error if some test env failed
            :failed
          else
            response["status"]
          end
        else
          :error
        end

      { commit_status: status }
    end

    def build_page(sha, ref)
      Gitlab::Utils.append_path(
        drone_url,
        "gitlab/#{project.full_path}/redirect/commits/#{sha}?branch=#{Addressable::URI.encode_component(ref.to_s)}")
    end

    def title
      'Drone'
    end

    def description
      s_('ProjectService|Run CI/CD pipelines with Drone.')
    end

    def self.to_param
      'drone_ci'
    end

    def help
      s_('ProjectService|Run CI/CD pipelines with Drone.')
    end

    def fields
      [
        {
          type: 'password',
          name: 'token',
          help: s_('ProjectService|Token for the Drone project.'),
          non_empty_password_title: s_('ProjectService|Enter new token'),
          non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'),
          required: true
        },
        {
          type: 'text',
          name: 'drone_url',
          title: s_('ProjectService|Drone server URL'),
          placeholder: 'http://drone.example.com',
          required: true
        }
      ]
    end

    override :hook_url
    def hook_url
      [drone_url, "/hook", "?owner=#{project.namespace.full_path}", "&name=#{project.path}", "&access_token=#{token}"].join
    end

    override :update_web_hook!
    def update_web_hook!
      # If using a service template, project may not be available
      super if project
    end

    def enable_ssl_verification
      original_value = Gitlab::Utils.to_boolean(properties['enable_ssl_verification'])
      original_value.nil? ? (new_record? || url_is_saas?) : original_value
    end

    private

    def url_is_saas?
      parsed_url = Addressable::URI.parse(drone_url)
      parsed_url&.scheme == 'https' && parsed_url.hostname == DRONE_SAAS_HOSTNAME
    rescue Addressable::URI::InvalidURIError
      false
    end
  end
end