summaryrefslogtreecommitdiff
path: root/app/models/project_services/issue_tracker_service.rb
blob: 19a5b4a74bb9a20409930f5d367a6ea1b2faa8c6 (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
143
144
145
146
147
148
149
150
151
152
# frozen_string_literal: true

class IssueTrackerService < Service
  validate :one_issue_tracker, if: :activated?, on: :manual_change

  # TODO: we can probably just delegate as part of
  # https://gitlab.com/gitlab-org/gitlab/issues/29404
  data_field :project_url, :issues_url, :new_issue_url

  default_value_for :category, 'issue_tracker'

  before_validation :handle_properties
  before_validation :set_default_data, on: :create

  # Pattern used to extract links from comments
  # Override this method on services that uses different patterns
  # This pattern does not support cross-project references
  # The other code assumes that this pattern is a superset of all
  # overridden patterns. See ReferenceRegexes.external_pattern
  def self.reference_pattern(only_long: false)
    if only_long
      /(\b[A-Z][A-Z0-9_]*-)#{Gitlab::Regex.issue}/
    else
      /(\b[A-Z][A-Z0-9_]*-|#{Issue.reference_prefix})#{Gitlab::Regex.issue}/
    end
  end

  def handle_properties
    # this has been moved from initialize_properties and should be improved
    # as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
    return unless properties

    @legacy_properties_data = properties.dup
    data_values = properties.slice!('title', 'description')
    data_values.reject! { |key| data_fields.changed.include?(key) }
    data_values.slice!(*data_fields.attributes.keys)
    data_fields.assign_attributes(data_values) if data_values.present?

    self.properties = {}
  end

  def legacy_properties_data
    @legacy_properties_data ||= {}
  end

  def supports_data_fields?
    true
  end

  def data_fields
    issue_tracker_data || self.build_issue_tracker_data
  end

  def default?
    default
  end

  def issue_url(iid)
    issues_url.gsub(':id', iid.to_s)
  end

  def issue_tracker_path
    project_url
  end

  def new_issue_path
    new_issue_url
  end

  def issue_path(iid)
    issue_url(iid)
  end

  def fields
    [
      { type: 'text', name: 'project_url', title: _('Project URL'), required: true },
      { type: 'text', name: 'issues_url', title: s_('ProjectService|Issue URL'), required: true },
      { type: 'text', name: 'new_issue_url', title: s_('ProjectService|New issue URL'), required: true }
    ]
  end

  def initialize_properties
    {}
  end

  # Initialize with default properties values
  def set_default_data
    return unless issues_tracker.present?

    # we don't want to override if we have set something
    return if project_url || issues_url || new_issue_url

    data_fields.project_url = issues_tracker['project_url']
    data_fields.issues_url = issues_tracker['issues_url']
    data_fields.new_issue_url = issues_tracker['new_issue_url']
  end

  def self.supported_events
    %w(push)
  end

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

    message = "#{self.type} was unable to reach #{self.project_url}. Check the url and try again."
    result = false

    begin
      response = Gitlab::HTTP.head(self.project_url, verify: true)

      if response
        message = "#{self.type} received response #{response.code} when attempting to connect to #{self.project_url}"
        result = true
      end
    rescue Gitlab::HTTP::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, OpenSSL::SSL::SSLError => error
      message = "#{self.type} had an error when trying to connect to #{self.project_url}: #{error.message}"
    end
    log_info(message)
    result
  end

  def support_close_issue?
    false
  end

  def support_cross_reference?
    false
  end

  private

  def enabled_in_gitlab_config
    Gitlab.config.issues_tracker &&
      Gitlab.config.issues_tracker.values.any? &&
      issues_tracker
  end

  def issues_tracker
    Gitlab.config.issues_tracker[to_param]
  end

  def one_issue_tracker
    return if template? || instance?
    return if project.blank?

    if project.services.external_issue_trackers.where.not(id: id).any?
      errors.add(:base, _('Another issue tracker is already in use. Only one issue tracker service can be active at a time'))
    end
  end
end

IssueTrackerService.prepend_if_ee('EE::IssueTrackerService')