class RoboPigeon::Jira::Ticket

Constants

ISSUE_PATH
MAX_TRANSITIONS

Attributes

assignee[RW]
description[RW]
duedate[RW]
fields[RW]
issue_type[RW]
project[RW]
reporter[RW]
summary[RW]
ticket[RW]

Public Class Methods

new(ticket = nil) click to toggle source
# 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

Public Instance Methods

add_comment(comment) click to toggle source
# 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) click to toggle source
# 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_server() click to toggle source
# 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!() click to toggle source
# 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_state() click to toggle source
# 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_request() click to toggle source
# File lib/robopigeon/jira/ticket.rb, line 31
def jira_request
  RoboPigeon::Jira::Client.jira_request
end
perform_transition(transition) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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

Private Instance Methods

array_of(values, field_metadata) click to toggle source
# File lib/robopigeon/jira/ticket.rb, line 183
def array_of(values, field_metadata)
  raise TypeError('provided Jira field must be an array') unless field_metadata['schema']['type'] == 'array'

  values.split(',').map do |value|
    value.strip!

    # Construct item based on its type if available
    if field_metadata.key?('schema') && field_metadata['schema'].key?('items')
      case field_metadata['schema']['items']
      when 'string'
        value
      when 'option'
        { value: value }
      else
        # Not really sure if this is the best default format
        { name: value }
      end
    else
      # Not really sure if this condition can happen
      # Not really sure if this is the best default format
      { name: value }
    end
  end
end
require_field(field) click to toggle source
# File lib/robopigeon/jira/ticket.rb, line 179
def require_field(field)
  raise RoboPigeon::Jira::RequiredFieldNotSet, "You must set a #{field}" if send(field).nil?
end
require_ticket() click to toggle source
# File lib/robopigeon/jira/ticket.rb, line 175
def require_ticket
  raise RoboPigeon::Jira::TicketNotFoundOrSet, 'Ticket was not set!' if ticket.nil?
end