Class: RoboPigeon::Jira::Ticket

Inherits:
Object
  • Object
show all
Defined in:
lib/robopigeon/jira/ticket.rb

Constant Summary collapse

MAX_TRANSITIONS =
10
ISSUE_PATH =
'/rest/api/2/issue'.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ticket = nil) ⇒ Ticket

Returns a new instance of Ticket.



10
11
12
13
14
15
# File 'lib/robopigeon/jira/ticket.rb', line 10

def initialize(ticket = nil)
  self.ticket = ticket
  self.fields = {}
  attempt_update_from_server
  self.project = ticket.split('-')[0] if ticket
end

Instance Attribute Details

#assigneeObject

Returns the value of attribute assignee.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def assignee
  @assignee
end

#descriptionObject

Returns the value of attribute description.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def description
  @description
end

#duedateObject

Returns the value of attribute duedate.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def duedate
  @duedate
end

#fieldsObject

Returns the value of attribute fields.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def fields
  @fields
end

#issue_typeObject

Returns the value of attribute issue_type.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def issue_type
  @issue_type
end

#projectObject

Returns the value of attribute project.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def project
  @project
end

#reporterObject

Returns the value of attribute reporter.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def reporter
  @reporter
end

#summaryObject

Returns the value of attribute summary.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def summary
  @summary
end

#ticketObject

Returns the value of attribute ticket.



7
8
9
# File 'lib/robopigeon/jira/ticket.rb', line 7

def ticket
  @ticket
end

Instance Method Details

#add_comment(comment) ⇒ Object



163
164
165
166
167
168
169
170
171
# File 'lib/robopigeon/jira/ticket.rb', line 163

def add_comment(comment)
  require_ticket

  post = jira_request.post do |req|
    req.url "#{ISSUE_PATH}/#{ticket}/comment"
    req.body = { body: comment }.to_json
  end
  raise 'Failed to create comment' unless post.status == 201
end

#assign(user_email) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/robopigeon/jira/ticket.rb', line 58

def assign(user_email)
  user_data = jira_request.get("/rest/api/2/user/search?username=#{user_email}")
  user = JSON.parse(user_data.body).first
  raise "Unable to find jira user with email #{user_email}" unless user

  self.assignee = user['name']
  self.reporter ||= user['name']

  if ticket
    jira_request.post do |req|
      req.url "/rest/api/3/issue/#{ticket}/assignee"
      req.body = { name: assignee }.to_json
    end
  end
end

#attempt_update_from_serverObject



17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/robopigeon/jira/ticket.rb', line 17

def attempt_update_from_server
  return unless ticket

  get = jira_request.get("#{ISSUE_PATH}/#{ticket}")
  raise "Failed to look up issue #{ticket}" unless get.status < 400

  raw = JSON.parse(get.body)
  self.project = raw['fields']['project']['key']
  self.issue_type = raw['fields']['issuetype']['name']
  self.summary = raw['fields']['summary']
  self.reporter = raw['fields']['reporter']['name'] if raw['fields']['reporter']
  self.assignee = raw['fields']['assignee']['name'] if raw['fields']['assignee']
end

#create!Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/robopigeon/jira/ticket.rb', line 35

def create!
  response = jira_request.post do |req|
    req.url '/rest/api/2/issue'
    req.body = {
      fields: {
        project: { key: project },
        issuetype: { name: issue_type },
        summary: summary,
        description: description,
        assignee: { name: reporter }
      }.merge(fields)
    }.to_json
  end

  begin
    self.ticket = JSON.parse(response.body).fetch('key')
    RoboPigeon::Jira::Client.last_created_ticket = ticket
    File.write('last_created_jira_ticket', ticket)
  rescue KeyError
    raise RoboPigeon::Jira::RequiredFieldNotSet, "Response from JIRA did not contain new issue key: #{response.body}"
  end
end

#current_stateObject



139
140
141
142
143
144
145
# File 'lib/robopigeon/jira/ticket.rb', line 139

def current_state
  require_ticket
  get = jira_request.get do |req|
    req.url "#{ISSUE_PATH}/#{ticket}"
  end
  JSON.parse(get.body)['fields']['status']['name']
end

#jira_requestObject



31
32
33
# File 'lib/robopigeon/jira/ticket.rb', line 31

def jira_request
  RoboPigeon::Jira::Client.jira_request
end

#perform_transition(transition) ⇒ Object



125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/robopigeon/jira/ticket.rb', line 125

def perform_transition(transition)
  require_ticket
  get_fields = jira_request.get("#{ISSUE_PATH}/#{ticket}?expand=transitions.fields")
  transition_details = JSON.parse(get_fields.body)['transitions'].find do |trans|
    trans['name'].casecmp(transition).zero?
  end
  raise "Unable to find valid transition '#{transition}'" unless transition_details

  jira_request.post do |req|
    req.url "#{ISSUE_PATH}/#{ticket}/transitions"
    req.body = { transition: { id: transition_details['id'] } }.to_json
  end
end

#set_field(name, value) ⇒ Object



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
# File 'lib/robopigeon/jira/ticket.rb', line 84

def set_field(name, value)
  require_field(:issue_type)
  request_path = "#{ISSUE_PATH}/createmeta?projectKeys=#{project}&issuetypeNames=#{issue_type}&expand=projects.issuetypes.fields"
  response = jira_request.get(request_path)
  raw = JSON.parse(response.body)
  fields = raw['projects'].first['issuetypes'].first['fields']
  field = fields.keys.select do |key|
    fields[key]['name'] == name
  end.first

  raise "Field #{name} was not found" unless field

  self.fields[field] = if fields[field]['schema']['type'] == 'array'
                         array_of(value, fields[field])
                       elsif fields[field]['allowedValues'].nil?
                         value
                       else
                         { value: value }
                       end

  if ticket
    post = jira_request.put do |req|
      req.url "#{ISSUE_PATH}/#{ticket}"
      req.body = { fields: self.fields }.to_json
    end
  end

  raise 'Failed to update field' unless post.nil? || post.status < 400
end

#set_issuetype(name) ⇒ Object



114
115
116
117
118
119
120
121
122
123
# File 'lib/robopigeon/jira/ticket.rb', line 114

def set_issuetype(name)
  require_field(:project)
  request_path = "#{ISSUE_PATH}/createmeta?projectKeys=#{project}&expand=projects.issuetypes.fields"
  response = jira_request.get(request_path)
  raw = JSON.parse(response.body)
  types = raw['projects'].first['issuetypes'].map { |type| type['name'] }
  raise RoboPigeon::Jira::FieldDoesNotConform, "Issue type #{name} was not found in #{types.join(', ')}" unless types.include?(name)

  self.issue_type = name
end

#set_reporter(user_email) ⇒ Object



74
75
76
77
78
79
80
81
82
# File 'lib/robopigeon/jira/ticket.rb', line 74

def set_reporter(user_email)
  raise 'Cannot modify reporter' if ticket

  user_data = jira_request.get("/rest/api/2/user/search?username=#{user_email}")
  user = JSON.parse(user_data.body).first
  raise "Unable to find jira user with email #{user_email}" unless user

  self.reporter = user['name']
end

#wait_for_state!(state, timeout = RoboPigeon::Jira::Client.wait_for_state_timeout, time = Time.now, sleep_time = 15) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/robopigeon/jira/ticket.rb', line 147

def wait_for_state!(state, timeout = RoboPigeon::Jira::Client.wait_for_state_timeout, time = Time.now, sleep_time = 15)
  require_ticket
  waited = (Time.now - time).to_i
  minutes = waited / 60
  seconds = waited % 60
  if current_state == state
    puts "#{ticket} in #{state} after #{minutes} minutes #{seconds} seconds"
    return
  end
  raise RoboPigeon::Jira::WaitTimeout, "Timed out waiting for #{ticket} to transition to #{state} after #{minutes} minutes #{seconds} seconds" if (timeout.to_i - waited) <= 0

  puts "Still waiting for #{ticket} in #{state}... waited #{minutes} minutes #{seconds} seconds"
  sleep sleep_time
  wait_for_state!(state, timeout, time, sleep_time)
end