TicketAbstractorClient

Client for accessing to a TicketAbstractor service.

Table of contents


Installation

Add this line to your application's Gemfile:

gem 'ticket_abstractor_client', '>= 2.0.0'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install ticket_abstractor_client -v '2.x'

[table of contents]


Upgrading

Since version 2.0.0, you operate with ticket as PORO.

[table of contents]


Configuration

Base configuration options:

TicketAbstractorClient.configure do |config|
  config.ticket_abstractor_url = 'http://localhost:4567'
  config.security_token = 'security_token_1'
end

SSL options:

DEFAULT_SSL_OPTIONS = { verify_ssl: true }

For more available ssl options see SSL/TLS support

JIRA specific options:

jira_fields_meta stores meta information about each JIRA field. Meta information is refreshed automatically after jira_meta_expiration_period (604800 seconds by default, one week).

TicketAbstractorClient.configuration.jira_fields_meta(endpoint)

Meta information can be manually updated:

ServiceNow specific options:

snow_display_value, based on this value, the display value and/or the actual value in the database are retrieved.

  • SNOW_DISPLAY_VALUE_TRUE returns display values for all of the fields.
  • SNOW_DISPLAY_VALUE_FALSE returns actual values from the database. If a value is not specified, this parameter defaults to false.
  • SNOW_DISPLAY_VALUE_ALL returns both actual and display values.

    config.snow_display_value = TicketAbstractorClient::Configuration::SNOW_DISPLAY_VALUE_ALL

Trace communications

Allows you to see all request's and response's data for Client, Ticket, Comment or Attachment

# add to configuration file
config.trace_communications = true # false by default

# my_class.rb
class MyClass
  include TicketAbstractorClient

  def create_snow_ticket(ticket_params)
    snow_ticket = ServiceNow::Ticket.new(ticket_params).sync!

    snow_ticket.communications_stack do |communication_data|
      # do something
    end
  end
end

communications_stack method returns an array of CommunicationData objects with following attributes:

  • method
  • path
  • args
  • response
  • executed_at
  • total_response_time
  • ta_response_time
  • ts_response_time

args and response attributes may contain 'Binary content' text or 'Base64 string representation of content' text for attachments, text depends on ticketing system.

[table of contents]


Usage

Jira

Get ticket by id:

# get issue from default Jira instance (T&P)
TicketAbstractorClient::Jira::Ticket.fetch_by_id(ticket_id: 'ISSUE-1')

# get Jira endpoints
TicketAbstractorClient::Jira::Client.new.endpoints

# get issue from specific endpoint
TicketAbstractorClient::Jira::Ticket.fetch_by_id(ticket_id: 'ISSUE-1', endpoint: :tp)

Get tickets by query:

TicketAbstractorClient::Jira::Ticket.fetch_tickets_by_jql(query: 'project=ISSUE', endpoint: :tp)

Get ticket's comments:

ticket = TicketAbstractorClient::Jira::Ticket.fetch_by_id(ticket_id: 'ISSUE-1')
ticket.comments

# or

ticket_id = 'ISSUE-1'
endpoint = 'tp'
comments = TicketAbstractorClient::Jira::Comment.fetch(ticket_id, endpoint)

Get ticket's attachments:

ticket = TicketAbstractorClient::Jira::Ticket.fetch(ticket_id: 'ISSUE-1')
ticket.attachments

# or

ticket_id = 'ISSUE-1'
endpoint = 'tp'
attachments = TicketAbstractorClient::Jira::Attachment.fetch_by_id(ticket_id, endpoint)

Create ticket:

ticket_opts = {
  endpoint: 'tp'
  project: 'ISSUE'
  fields: {
    summary: "Example of ticket's summary",
    description: "Example of ticket's description",
    severity: 'Sev2',
    priority: 'P2',
    ...
  }
}

ticket = TicketAbstractorClient::Jira::Ticket.new(ticket_opts)
ticket.sync!
ticket.ticket_id # => ISSUE-111

Update ticket:

ticket_opts: {
  endpoint: 'tp'
  ticket_id: 'ISSUE-111'
  fields: {
    description: "Updated example of ticket's description",
    severity: 'Sev3',
    ...
  }
}

ticket = TicketAbstractorClient::Jira::Ticket.new(ticket_opts)
ticket.sync!
ticket.description # => "Updated example of ticket's description"

Update ticket's status:

ticket = TicketAbstractorClient::Jira::Ticket.new(ticket_id: 'ISSUE-111', endpoint: 'tp')
ticket.status = 'IN_PROGRESS'
ticket.sync!

Add comment:

include TicketAbstractorClient
...

ticket = Jira::Ticket.new(ticket_id: 'ISSUE-111', endpoint: 'tp')
ticket.add_comment(body: 'New comment body')
ticket.sync!

# or

Jira::Comment.new(ticket_id: 'ISSUE-111', endpoint: 'tp', body: 'New comment body').sync!

Add attachment:

include TicketAbstractorClient
...

ticket = Jira::Ticket.new(ticket_id: 'ISSUE-111', endpoint: 'tp')
ticket.add_attachment(file_attachment: '/path/to/file')
ticket.sync!

# or

Jira::Attachment.new(ticket_id: 'ISSUE-111', endpoint: 'tp', file_attachment: '/path/to/file').sync!

ServiceNow

Get ticket by id:

# get ServiceNow endpoints
TicketAbstractorClient::ServiceNow::Client.new.endpoints

# get issue from specific endpoint
ticket_opts = { ticket_id: 'INC001', endpoint: :dev, project: 'incident' }
TicketAbstractorClient::ServiceNow::Ticket.fetch_by_id(ticket_opts)

Get tickets by query:

ticket_opts = { sysparm_query: 'numberIN(INC001,INC002,INC010)', endpoint: :test, project: 'incident' }
TicketAbstractorClient::ServiceNow::Ticket.fetch_tickets_by_query(ticket_opts)

Get ticket's comments:

ticket_opts = { ticket_id: 'INC001', endpoint: :dev, project: 'incident' }
ticket = TicketAbstractorClient::ServiceNow::Ticket.fetch_by_id(ticket_opts)
ticket.comments

# or

ticket_id = 'INC001'
endpoint = 'default'
project = 'incident'
comments = TicketAbstractorClient::ServiceNow::Comment.fetch(ticket_id, endpoint, project)

Get ticket's attachments:

ticket_opts = { ticket_id: 'INC001', endpoint: :dev, project: :incident }
ticket = TicketAbstractorClient::ServiceNow::Ticket.fetch_by_id(ticket_opts)
ticket.attachments

# or

ticket_id = 'INC001'
endpoint = 'test'
project = 'incident'
attachments = TicketAbstractorClient::ServiceNow::Attachment.fetch(ticket_id, endpoint, project)

Create ticket:

ticket_opts = {
  endpoint: 'prod'
  project: 'incident'
  fields: {
    short_title: "Example of ticket's summary",
    title: "Example of ticket's description",
    u_severity: 'Sev2',
    u_priority: 'P2',
    ...
  }
}

ticket = TicketAbstractorClient::ServiceNow::Ticket.new(ticket_opts)
ticket.sync!
ticket.ticket_id # => INC011

Update ticket:

ticket_opts = {
  endpoint: 'prod'
  project: 'incident'
  ticket_id: 'INC011'
  fields: {
    title: "Updated example of ticket's description",
    u_severity: 'Sev3',
    ...
  }
}

ticket = TicketAbstractorClient::ServiceNow::Ticket.new(ticket_opts)
ticket.sync!
ticket.short_title # => "Updated example of ticket's description"

Update ticket's status:

ticket_opts = { ticket_id: 'INC011', endpoint: 'test', project: :incident }
ticket = TicketAbstractorClient::ServiceNow::Ticket.new(ticket_opts)
ticket.status = 'IN_PROGRESS'
ticket.sync!

Add comment:

include TicketAbstractorClient
...

ticket = ServiceNow::Ticket.new(ticket_id: 'INC011', endpoint: 'test', project: :incident)
ticket.add_comment(body: 'New comment body')
ticket.sync!

# or

ServiceNow::Comment.new(
  ticket_id: 'INC011',
  endpoint: 'test',
  project: :incident,
  body: 'New comment body'
).sync!

Add attachment:

include TicketAbstractorClient
...

ticket = ServiceNow::Ticket.new(ticket_id: 'INC011', endpoint: 'test', project: :incident)
ticket.add_attachment(file_attachment: '/path/to/file')
ticket.sync!

# or

ServiceNow::Attachment.new(
  ticket_id: 'INC011',
  endpoint: 'test',
  project: :incident,
  file_attachment: '/path/to/file'
).sync!

[table of contents]


Filtering fields

There is a situation when you need to convert some values, like datetimes, or skip any other values and so on, before you start working with fetched ticket. All you have to do is create a class that is inherited from TicketAbstractorClient::Base::TicketsFilter and implement a filter_ticket method, after that configure the gem to use your class.

ServiceNow example:

class MyServiceNowTicketsFilter < TicketAbstractorClient::Base::TicketsFilter
  def initialize(raw_ticket)
    super(raw_ticket)
  end

  def filter_ticket
    @ticket.fields = @ticket.fields.each_with_object([]) do |raw_field, filtered_fields|
      # do some filtering here
    end

    @ticket
  end
end

Add a line to configuration

...
config.snow_fields_filter_class = MyServiceNowTicketsFilter
...

That's it.

JIRA is supported as well.

[table of contents]


TODOs

  • [] Ability to retrieve communications_stack data for Jira objects (Ticket, Comment and Attachment)

[table of contents]


Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

[table of contents]