Class: Jiraby::Jira

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

Overview

Wrapper for Jira

Constant Summary collapse

@@max_results =
50

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url, username, password, api_version = '2') ⇒ Jira

Initialize a Jira instance at the given URL.

TODO: Handle the case where the wrong API version is used for a given Jira instance (should give 404s when resources are requested)

Parameters:

  • url (String)

    Full URL of the JIRA instance to connect to. If this does not begin with http: or https:, then http:// is assumed.

  • username (String)

    Jira username

  • password (String)

    Jira password

  • api_version (String) (defaults to: '2')

    The API version to use. For now, only '2' is supported.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/jiraby/jira.rb', line 35

def initialize(url, username, password, api_version='2')
  if !known_api_versions.include?(api_version)
    raise ArgumentError.new("Unknown Jira API version: #{api_version}")
  end

  # Prepend http:// and remove trailing slashes
  url = "http://#{url}" if url !~ /https:|http:/
  url.gsub!(/\/+$/, '')
  @url = url

  @credentials = {:user => username, :password => password}
  @api_version = api_version
  @_field_mapping = nil

  # All REST API access is done through the @rest attribute
  @rest = Jiraby::JSONResource.new(base_url, @credentials)
end

Instance Attribute Details

#api_versionObject (readonly)

initialize



53
54
55
# File 'lib/jiraby/jira.rb', line 53

def api_version
  @api_version
end

#restObject (readonly)

initialize



53
54
55
# File 'lib/jiraby/jira.rb', line 53

def rest
  @rest
end

#urlObject (readonly)

initialize



53
54
55
# File 'lib/jiraby/jira.rb', line 53

def url
  @url
end

Instance Method Details

#_path_with_query(path, query = {}) ⇒ Object

Return a URL query, suitable for use in a GET/DELETE/HEAD request that accepts queries like ?var1=value1&var2=value2.



89
90
91
92
93
94
95
96
97
# File 'lib/jiraby/jira.rb', line 89

def _path_with_query(path, query={})
  # TODO: Escape special chars
  params = query.map {|k,v| "#{k}=#{v}"}.join("&")
  if params.empty?
    return path
  else
    return "#{path}?#{params}"
  end
end

#auth_urlObject

Return the URL for authenticating to Jira.



64
65
66
# File 'lib/jiraby/jira.rb', line 64

def auth_url
  "#{@url}/rest/auth/1/session"
end

#base_urlObject

auth_url



68
69
70
# File 'lib/jiraby/jira.rb', line 68

def base_url
  "#{@url}/rest/api/#{@api_version}"
end

#count(jql = '') ⇒ Integer

Return the total number of issues matching the given JQL query, or the count of all issues if no JQL query is given.

Parameters:

  • jql (String) (defaults to: '')

    JQL query for the issues you want to match

Returns:

  • (Integer)

    Number of issues matching the query



277
278
279
280
281
282
283
284
285
# File 'lib/jiraby/jira.rb', line 277

def count(jql='')
  result = self.post 'search', {
    :jql => jql,
    :startAt => 0,
    :maxResults => 1,
    :fields => [''],
  }
  return result.total
end

#create_issue(project_key, issue_type = 'Bug') ⇒ Issue

Create a new issue

Parameters:

  • project_key (String)

    Identifier for the project to create the issue under

  • issue_type (String) (defaults to: 'Bug')

    The name of an issue type. May be any issue types accepted by the given project; typically "Bug", "Task", "Improvement", "New Feature", or "Sub-task"

Returns:



224
225
226
227
228
229
230
# File 'lib/jiraby/jira.rb', line 224

def create_issue(project_key, issue_type='Bug')
  issue_data = self.post 'issue', {
    "fields" => {"project" => {"key" => project_key} }
  }
  return Issue.new(self, issue_data) if issue_data
  return nil
end

#delete(path, query = {}) ⇒ Object



104
105
106
# File 'lib/jiraby/jira.rb', line 104

def delete(path, query={})
  @rest[_path_with_query(path, query)].delete
end

#enumerator(method, path, params = {}, list_key = nil) ⇒ Object

Return an Enumerator yielding items returned by a REST method that accepts startAt and maxResults parameters. This allows you to iterate through large data sets.

Parameters:

  • method (String, Symbol)

    HTTP request method to use (:get or :post)

  • path (String)

    Relative path to the REST method (such as user/search)

  • params (Hash) (defaults to: {})

    GET or POST parameters to submit (depending on which method and path you're requesting)

  • list_key (String) (defaults to: nil)

    For REST methods returning an array embedded in an object (like search and dashboard), the attribute name where the array of things is stored.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/jiraby/jira.rb', line 153

def enumerator(method, path, params={}, list_key=nil)
  max_results = @@max_results
  return Enumerator.new do |enum|
    page = 0
    more = true
    while(more) do
      paged_params = params.merge({
        :startAt => page * max_results,
        :maxResults => max_results
      })
      response = self.send(method, path, paged_params)

      # Some methods (like 'search') return an Entity, with the list of
      # items indexed by `list_key`.
      if response.is_a?(Jiraby::Entity)
        items = response[list_key]
      # Others (like 'user/search') return an array of Entity.
      elsif response.is_a?(Array)
        items = response
      else
        raise RuntimeError.new("Unexpected data: #{response}")
      end

      items.to_a.each do |item|
        enum << item
      end

      if items.to_a.count < max_results
        more = false
      else
        page += 1
      end
    end # while(more)
  end # Enumerator.new
end

#field_mappingObject

Return a hash of 'field_id' => 'Field Name' for all fields



289
290
291
292
293
294
295
# File 'lib/jiraby/jira.rb', line 289

def field_mapping
  if @_field_mapping.nil?
    ids_and_names = self.get('field').collect { |f| [f.id, f.name] }
    @_field_mapping = Hash[ids_and_names]
  end
  return @_field_mapping
end

#get(path, query = {}) ⇒ Object

REST wrapper methods returning Jiraby::Entity



100
101
102
# File 'lib/jiraby/jira.rb', line 100

def get(path, query={})
  @rest[_path_with_query(path, query)].get
end

#issue(key) ⇒ Issue

Return the Issue with the given key.

Parameters:

  • key (String)

    The issue's unique identifier (usually like PROJ-NNN)

Returns:

  • (Issue)

    An Issue populated with data returned by the API

Raises:

  • (IssueNotFound)

    If the issue was not found or fetching failed



200
201
202
203
204
205
206
207
208
209
210
# File 'lib/jiraby/jira.rb', line 200

def issue(key)
  if key.nil? || key.to_s.strip.empty?
    raise ArgumentError.new("Issue key is required")
  end
  json = self.get "issue/#{key}"
  if json and (json.empty? or json['errorMessages'])
    raise IssueNotFound.new("Issue '#{key}' not found in Jira")
  else
    return Issue.new(self, json)
  end
end

#known_api_versionsObject

Return a list of known Jira API versions.



57
58
59
# File 'lib/jiraby/jira.rb', line 57

def known_api_versions
  return ['2']
end

#not_implemented_in(feature, *api_versions) ⇒ Object

Raise an exception if the current API version is one of those listed.

Parameters:

  • feature (String)

    Name or short description of the feature in question

  • api_versions (Array)

    One or more version strings for Jira APIs that do not support the feature in question



80
81
82
83
84
85
# File 'lib/jiraby/jira.rb', line 80

def not_implemented_in(feature, *api_versions)
  if api_versions.include?(@api_version)
    raise NotImplementedError,
      "#{feature} not supported by version #{@api_version} of the Jira API"
  end
end

#post(path, data) ⇒ Object



112
113
114
# File 'lib/jiraby/jira.rb', line 112

def post(path, data)
  @rest[path].post data
end

#project(key) ⇒ Project

Return the Project with the given key.

Parameters:

  • key (String)

    The project's unique identifier (usually like PROJ)

Returns:

  • (Project)

    A Project populated with data returned by the API, or nil if no such project is found.



242
243
244
245
246
247
248
249
# File 'lib/jiraby/jira.rb', line 242

def project(key)
  json = self.get "project/#{key}"
  if json and (json.empty? or json['errorMessages'])
    raise ProjectNotFound.new("Project '#{key}' not found in Jira")
  else
    return Project.new(json)
  end
end

#project_meta(project_key) ⇒ Object

Return the 'createmeta' data for the given project key, or nil if the project is not found.

TODO: Move this into the Project class?



257
258
259
260
261
262
263
264
265
# File 'lib/jiraby/jira.rb', line 257

def project_meta(project_key)
  meta = self.get 'issue/createmeta?expand=projects.issuetypes.fields'
   = meta.projects.find {|proj| proj['key'] == project_key}
  if  and !.nil?
    return 
  else
    raise ProjectNotFound.new("Project '#{project_key}' not found in Jira")
  end
end

#put(path, data) ⇒ Object



108
109
110
# File 'lib/jiraby/jira.rb', line 108

def put(path, data)
  @rest[path].put data
end

#search(jql_query) ⇒ Enumerator

Find all issues matching the given JQL query, and return an Enumerator that yields each one as an Issue object. Each Issue is fetched from the REST API as needed.

Parameters:

  • jql_query (String)

    JQL query for the issues you want to match

Returns:

  • (Enumerator)


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

def search(jql_query)
  params = {
    :jql => jql_query,
  }
  issues = self.enumerator(:post, 'search', params, 'issues')
  return Enumerator.new do |e|
    issues.each do |data|
      e << Issue.new(self, data)
    end
  end
end