jiralicious 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/jiralicious.rb CHANGED
@@ -22,15 +22,26 @@ require 'jiralicious/basic_session'
22
22
  require 'jiralicious/cookie_session'
23
23
  require 'jiralicious/configuration'
24
24
 
25
+ ##
26
+ # The Jiralicious module standard options and methods
27
+ #
25
28
  module Jiralicious
29
+ # Adds Configuration functionality
26
30
  extend Configuration
31
+ # Adds self functionality
27
32
  extend self
28
33
 
34
+ ##
35
+ # Processes the session information and returns the current session object
36
+ #
29
37
  def session
30
38
  session_type = "#{self.auth_type.to_s.capitalize}Session"
31
39
  @session ||= Jiralicious.const_get(session_type).new
32
40
  end
33
41
 
42
+ ##
43
+ # Returns the currently defined Rest API path
44
+ #
34
45
  def rest_path
35
46
  "#{self.uri}/rest/api/#{self.api_version}"
36
47
  end
@@ -1,13 +1,27 @@
1
- # To change this template, choose Tools | Templates
2
- # and open the template in the editor.
1
+ # encoding: utf-8
3
2
  require "uri"
4
3
  module Jiralicious
4
+ ##
5
+ # The Base class encapsulates all of the default functionality necessary in order
6
+ # to properly manage the Hashie::Trash object within the Jiralicious framework.
7
+ #
5
8
  class Base < Hashie::Trash
9
+
10
+ ##
11
+ # Includes functionality from FieldParser
12
+ #
6
13
  include Jiralicious::Parsers::FieldParser
7
14
 
15
+ ##
16
+ # Used to identify if the class has been loaded
17
+ #
8
18
  attr_accessor :loaded
9
19
 
10
- ### Trash Extention Methods ###
20
+ ##
21
+ # Trash Extention properties_from_hash
22
+ # Adds an underscore (_) before a numeric field.
23
+ # This ensures that numeric fields will be treated as strings.
24
+ #
11
25
  def properties_from_hash(hash)
12
26
  hash.inject({}) do |newhash, (k, v)|
13
27
  k = k.gsub("-", "_")
@@ -18,8 +32,11 @@ module Jiralicious
18
32
  end
19
33
  end
20
34
 
21
- ### Class Methods ###
22
35
  class << self
36
+ ##
37
+ # Finds the specified key in relation to the current class. This is based on the
38
+ # inheritance and will create an error if called from the Base Class directly.
39
+ #
23
40
  def find(key, options = {})
24
41
  response = fetch({:key => key})
25
42
  if options[:reload] == true
@@ -29,20 +46,36 @@ module Jiralicious
29
46
  end
30
47
  end
31
48
 
49
+ ##
50
+ # Searches for all objects of the inheritance class. This method can create very large
51
+ # datasets and is not recommended for any request that could slow down either Jira or
52
+ # the Ruby application.
53
+ #
32
54
  def find_all
33
55
  response = fetch()
34
56
  new(response)
35
57
  end
36
58
 
59
+ ##
60
+ # Generates the endpoint_name based on the current inheritance class.
61
+ #
37
62
  def endpoint_name
38
63
  self.name.split('::').last.downcase
39
64
  end
40
65
 
66
+ ##
67
+ # Generates the parent_name based on the current inheritance class.
68
+ #
41
69
  def parent_name
42
70
  arr = self.name.split('::')
43
71
  arr[arr.length-2].downcase
44
72
  end
45
73
 
74
+ ##
75
+ # uses the options to build the URI options necessary to handle the request.
76
+ # Some options are defaulted if not explicit while others are only necessary
77
+ # under specific conditions.
78
+ #
46
79
  def fetch(options = {})
47
80
  options[:method] = :get unless [:get, :post, :put, :delete].include?(options[:method])
48
81
  options[:parent_uri] = "#{parent_name}/#{options[:parent_key]}/" unless options[:parent].nil?
@@ -59,6 +92,10 @@ module Jiralicious
59
92
  Jiralicious.session.request(options[:method], options[:url_uri], :handler => handler, :body => options[:body_uri].to_json)
60
93
  end
61
94
 
95
+ ##
96
+ # Configures the default handler. This can be overridden in
97
+ # the child class to provide additional error handling.
98
+ #
62
99
  def handler
63
100
  Proc.new do |response|
64
101
  case response.code
@@ -77,26 +114,48 @@ module Jiralicious
77
114
  alias :all :find_all
78
115
  end
79
116
 
80
- ### Instance Methods ###
117
+ ##
118
+ # Generates the endpoint_name based on the current inheritance class.
119
+ #
81
120
  def endpoint_name
82
121
  self.class.endpoint_name
83
122
  end
84
123
 
124
+ ##
125
+ # Generates the parent_name based on the current inheritance class.
126
+ #
85
127
  def parent_name
86
128
  self.class.parent_name
87
129
  end
88
130
 
131
+ ##
132
+ # Searches for all objects of the inheritance class. This method can create very large
133
+ # datasets and is not recommended for any request that could slow down either Jira or
134
+ # the Ruby application.
135
+ #
89
136
  def all
90
137
  self.class.all
91
138
  end
92
139
 
140
+ ##
141
+ # Returns the the logical form of the loaded member. This used
142
+ # to determine if the object is loaded and ready for usage.
143
+ #
93
144
  def loaded?
94
- self.loaded
145
+ !!self.loaded
95
146
  end
96
147
 
148
+ ##
149
+ # Default reload method is blank. For classes that implement lazy loading
150
+ # this method will be overridden with the necessary functionality.
151
+ #
97
152
  def reload
98
153
  end
99
154
 
155
+ ##
156
+ # Overrides the default method_missing check. This override is used in lazy
157
+ # loading to ensure that the requested field or method is truly unavailable.
158
+ #
100
159
  def method_missing(meth, *args, &block)
101
160
  if !loaded?
102
161
  self.loaded = true
@@ -107,6 +166,9 @@ module Jiralicious
107
166
  end
108
167
  end
109
168
 
169
+ ##
170
+ # Validates if the provided object is a numeric value
171
+ #
110
172
  def numeric?(object)
111
173
  true if Float(object) rescue false
112
174
  end
@@ -1,5 +1,12 @@
1
1
  module Jiralicious
2
+ ##
3
+ # The BasicSesion class extends the default Session class by forcing
4
+ # basic_auth to be fired prior to any other action.
5
+ #
2
6
  class BasicSession < Session
7
+ ##
8
+ # Fires off the basic_auth with the local username and password.
9
+ #
3
10
  def before_request
4
11
  self.class.basic_auth(Jiralicious.username, Jiralicious.password)
5
12
  end
@@ -2,17 +2,25 @@
2
2
  require 'ostruct'
3
3
  module Jiralicious
4
4
  module Configuration
5
+ # Array of available attributes
5
6
  VALID_OPTIONS = [:username, :password, :uri, :api_version, :auth_type]
7
+ # Default user name set prior to login attempt
6
8
  DEFAULT_USERNAME = nil
9
+ # Default password set prior to login attempt
7
10
  DEFAULT_PASSWORD = nil
11
+ # Authentication is either :basic or :cookie (depricated)
8
12
  DEFAULT_AUTH_TYPE = :basic
13
+ # Default URI set prior to login attempt
9
14
  DEFAULT_URI = nil
15
+ # Default API Version can be set any valid version or "latest"
10
16
  DEFAULT_API_VERSION = "latest"
11
17
 
18
+ # Enables block configuration mode
12
19
  def configure
13
20
  yield self
14
21
  end
15
22
 
23
+ # Provides access to the array of attributes
16
24
  attr_accessor *VALID_OPTIONS
17
25
 
18
26
  # Reset when extended into class
@@ -20,12 +28,14 @@ module Jiralicious
20
28
  base.reset
21
29
  end
22
30
 
31
+ # Pass options to set the values
23
32
  def options
24
33
  VALID_OPTIONS.inject({}) do |option, key|
25
34
  option.merge!(key => send(key))
26
35
  end
27
36
  end
28
37
 
38
+ # Resets all attributes to default values
29
39
  def reset
30
40
  self.username = DEFAULT_USERNAME
31
41
  self.password = DEFAULT_PASSWORD
@@ -34,6 +44,18 @@ module Jiralicious
34
44
  self.auth_type = DEFAULT_AUTH_TYPE
35
45
  end
36
46
 
47
+ ##
48
+ # Loads the provided YML file.
49
+ #
50
+ # Can provide either direct or relational path to the file. It is recommended to send a direct path
51
+ # due to dynamic loading and/or different file locations due to different deployment methods.
52
+ #
53
+ # [Direct Path] /usr/project/somepath_to_file/jira.yml
54
+ #
55
+ # [Relational Path] Rails.root.to_s + "/config/jira.yml"
56
+ #
57
+ # "./config/jira.yml"
58
+ #
37
59
  def load_yml(yml_file)
38
60
  if File.exist?(yml_file)
39
61
  yml_cfg = OpenStruct.new(YAML.load_file(yml_file))
@@ -1,17 +1,26 @@
1
1
  # encoding: utf-8
2
-
3
2
  module Jiralicious
3
+ ##
4
+ # The CookieSesssion class extends the Session class with the
5
+ # functionality of utilizing cookies for authorization management.
6
+ #
7
+ # Deprecated:: CookieSession is deprecated as of version 0.2.0
8
+ #
4
9
  class CookieSession < Session
10
+ # Adds attributes to the CookieSession
5
11
  attr_accessor :authenticating, :session, :login_info
6
12
 
13
+ # Checks to see if session is active
7
14
  def alive?
8
15
  @session && @login_info
9
16
  end
10
17
 
18
+ # Provides login information on every request
11
19
  def before_request
12
20
  self.login if require_login? && !@authenticating
13
21
  end
14
22
 
23
+ # Handles the response from the request
15
24
  def after_request(response)
16
25
  unless @authenticating
17
26
  if captcha_required(response)
@@ -26,6 +35,7 @@ module Jiralicious
26
35
  @authenticating = false
27
36
  end
28
37
 
38
+ # Authenticates the login
29
39
  def login
30
40
  @authenticating = true
31
41
  handler = Proc.new do |response|
@@ -54,6 +64,7 @@ module Jiralicious
54
64
 
55
65
  end
56
66
 
67
+ # Logs out of the API
57
68
  def logout
58
69
  handler = Proc.new do |request|
59
70
  if response.code == 204
@@ -74,6 +85,7 @@ module Jiralicious
74
85
 
75
86
  private
76
87
 
88
+ # Handles Captcha if necessary
77
89
  def captcha_required(response)
78
90
  response.code == 401 &&
79
91
  # Fakeweb lowercases headers automatically. :(
@@ -81,14 +93,17 @@ module Jiralicious
81
93
  response.headers["x-seraph-loginreason"] == "AUTHENTICATION_DENIED")
82
94
  end
83
95
 
96
+ # Throws if cookie is invalid
84
97
  def cookie_invalid(response)
85
98
  response.code == 401 && response.body =~ /cookie/i
86
99
  end
87
100
 
101
+ # Checks to see if login is required
88
102
  def require_login?
89
103
  !(Jiralicious.username.empty? && Jiralicious.password.empty?) && !alive?
90
104
  end
91
105
 
106
+ # Resets the current Session
92
107
  def clear_session
93
108
  @session = @login_info = nil
94
109
  end
@@ -1,7 +1,14 @@
1
- # To change this template, choose Tools | Templates
2
- # and open the template in the editor.
1
+ # encoding: utf-8
3
2
  module Jiralicious
3
+ ##
4
+ # The CustomFieldOption provides a list of available custom field options. This method is
5
+ # used in lazy loading and can be used to validate options prior to updating the issue.
6
+ #
4
7
  class CustomFieldOption < Jiralicious::Base
8
+
9
+ ##
10
+ # Initialization Method
11
+ #
5
12
  def initialize(decoded_json, default = nil, &blk)
6
13
  @loaded = false
7
14
  if decoded_json.is_a? Hash
@@ -13,10 +20,17 @@ module Jiralicious
13
20
  end
14
21
 
15
22
  class << self
23
+ ##
24
+ # Overrides the auto-generated endpoint_name from Base.
25
+ # This is necessary due to lower camel case naming convention.
26
+ #
16
27
  def endpoint_name
17
28
  "customFieldOption"
18
29
  end
19
30
 
31
+ ##
32
+ # Retrieves the options based on the ID
33
+ #
20
34
  def find(id, options = {})
21
35
  response = fetch({:key => id})
22
36
  response.parsed_response['id'] = id
@@ -1,8 +1,16 @@
1
- # To change this template, choose Tools | Templates
2
- # and open the template in the editor.
1
+ # encoding: utf-8
3
2
  module Jiralicious
3
+ ##
4
+ # The Field class is used in multiple classes as a support object. This class
5
+ # is designed as a Object Oriented Method of viewing the Jira JSON/Hash.
6
+ #
4
7
  class Field < Jiralicious::Base
5
-
8
+ ##
9
+ # Initialization Method
10
+ #
11
+ # Builds the dynamic Field object from either a Hash or Array. The decoded JSON object can be nested
12
+ # as deep as necessary but it is recommended that JSON objects are no deeper then 5 levels maximum.
13
+ #
6
14
  def initialize(decoded_json, default = nil, &blk)
7
15
  @loaded = false
8
16
  if decoded_json.is_a? Hash
@@ -1,20 +1,36 @@
1
1
  # encoding: utf-8
2
2
  module Jiralicious
3
+ ##
4
+ # The Issue class rolls up all functionality of issues from jira. This class contains methods to manage
5
+ # Issues from Ruby via the API. Several child classes are added in order to facilitate several different
6
+ # aspects of managing the issues.
7
+ #
3
8
  class Issue < Jiralicious::Base
4
9
 
10
+ # Provides access to the Jira Key field
5
11
  property :jira_key, :from => :key
12
+ # Provides access to the expand fields
6
13
  property :expand
14
+ # Provides access to the self string
7
15
  property :jira_self, :from => :self
16
+ # Provides access to the field list
8
17
  property :fields
18
+ # Provides access to transitions
9
19
  property :transitions
20
+ # Provides access to the Jira id
10
21
  property :id
22
+ # Contains the Fields Class
11
23
  attr_accessor :fields
24
+ # Contains the Comments Class
12
25
  attr_accessor :comments
26
+ # Contains the Watchers Class
13
27
  attr_accessor :watchers
28
+ # Contains the createmeta
14
29
  attr_accessor :createmeta
30
+ # Contains the editmeta
15
31
  attr_accessor :editmeta
16
32
 
17
- ### Initialization ###
33
+ # Initialization Method
18
34
  def initialize(decoded_json = nil, default = nil, &blk)
19
35
  @loaded = false
20
36
  if (!decoded_json.nil?)
@@ -24,16 +40,22 @@ module Jiralicious
24
40
  @fields = Fields.new(self['fields']) if self['fields']
25
41
  @comments = Comment.find_by_key(self.jira_key)
26
42
  @watchers = Watchers.find_by_key(self.jira_key)
43
+ @transitions = Transitions.new(self.jira_key)
27
44
  @loaded = true
28
45
  end
29
46
  end
30
47
  @fields = Fields.new if @fields.nil?
31
48
  @comments = Comment.new if @comments.nil?
32
49
  @watchers = Watchers.new if @watchers.nil?
50
+ @transitions = Transitions.new if @transitions.nil?
33
51
  @createmeta = nil
34
52
  @editmeta = nil
35
53
  end
36
54
 
55
+ ##
56
+ # Imports all data from a decoded hash. This function is used when a blank
57
+ # issue is created but needs to be loaded from a JSON string at a later time.
58
+ #
37
59
  def load(decoded_hash, default = nil)
38
60
  decoded_hash.each do |k,v|
39
61
  self[:"#{k}"] = v
@@ -49,45 +71,77 @@ module Jiralicious
49
71
  end
50
72
  end
51
73
 
74
+ ##
75
+ # Forces the Jira Issue to reload with current or updated
76
+ # information. This method is used in lazy loading methods.
77
+ #
52
78
  def reload
53
79
  load(self.class.find(self.jira_key, {:reload => true}).parsed_response)
54
80
  end
55
81
 
56
-
57
- ### Class Methods ###
58
82
  class << self
83
+ ##
84
+ # Adds specified assignee to the Jira Issue.
85
+ #
59
86
  def assignee(name, key)
60
87
  name = {"name" => name} if name.is_a? String
61
88
  fetch({:method => :put, :key => "#{key}/assignee", :body => name})
62
89
  end
63
90
 
91
+ ##
92
+ # Creates a new issue. This method is not recommended
93
+ # for direct access but is provided for advanced users.
94
+ #
64
95
  def create(issue)
65
96
  fetch({:method => :post, :body => issue})
66
97
  end
67
98
 
99
+ ##
100
+ # Removes/Deletes the Issue from the Jira Project. It is not recommended to delete issues however the
101
+ # functionality is provided. It is recommended to override this function to throw an error or warning
102
+ # to maintain data integrity in systems that do not allow deleting from a remote location.
103
+ #
68
104
  def remove(key, options = {})
69
105
  fetch({:method => :delete, :body_to_params => true, :key => key, :body => options})
70
106
  end
71
107
 
108
+ ##
109
+ # Updates the specified issue based on the provided HASH. It is not recommended
110
+ # to access this method directly but is provided for advanced users.
111
+ #
72
112
  def update(issue, key)
73
113
  fetch({:method => :put, :key => key, :body => issue})
74
114
  end
75
115
 
116
+ ##
117
+ # Retrieves the create meta for the Jira Project based on Issue Types.
118
+ # Can be used to validate or filter create requests to minimize errors.
119
+ #
76
120
  def createmeta(projectkeys, issuetypeids = nil)
77
121
  response = fetch({:body_to_params => true, :key => "createmeta", :body => {:expand => "projects.issuetypes.fields.", :projectKeys => projectkeys, :issuetypeIds => issuetypeids}})
78
122
  return Field.new(response.parsed_response)
79
123
  end
80
124
 
125
+ ##
126
+ # Retrieves the edit meta for the Jira Issue. Can be used
127
+ # to validate or filter create requests to minimize errors.
128
+ #
81
129
  def editmeta(key)
82
130
  response = fetch({:key => "#{key}/editmeta"})
83
131
  response.parsed_response["key"] = key
84
132
  Field.new(response.parsed_response)
85
133
  end
86
134
 
135
+ ##
136
+ # Legacy method to retrieve transitions manually.
137
+ #
87
138
  def get_transitions(transitions_url)
88
139
  Jiralicious.session.request(:get, transitions_url, :handler => handler)
89
140
  end
90
141
 
142
+ ##
143
+ # Legacy method to process transitions manually.
144
+ #
91
145
  def transition(transitions_url, data)
92
146
  Jiralicious.session.request(:post, transitions_url,
93
147
  :handler => handler,
@@ -95,16 +149,24 @@ module Jiralicious
95
149
  end
96
150
  end
97
151
 
98
- ### Public Classes ###
99
-
152
+ ##
153
+ # Method to assign an assignee by name in a current issue.
154
+ #
100
155
  def set_assignee(name)
101
156
  self.class.assignee(name, self.jira_key)
102
157
  end
103
158
 
159
+ ##
160
+ # Method to remove or delete the current issue.
161
+ #
104
162
  def remove(options = {})
105
163
  self.class.remove(self.jira_key, options)
106
164
  end
107
165
 
166
+ ##
167
+ # Retrieves the create meta for the Jira Project based on Issue Types.
168
+ # Can be used to validate or filter create requests to minimize errors.
169
+ #
108
170
  def createmeta
109
171
  if @createmeta.nil?
110
172
  @createmeta = self.class.createmeta(self.jira_key.split("-")[0])
@@ -112,6 +174,10 @@ module Jiralicious
112
174
  @createmeta
113
175
  end
114
176
 
177
+ ##
178
+ # Retrieves the edit meta for the Jira Issue. Can be used
179
+ # to validate or filter create requests to minimize errors.
180
+ #
115
181
  def editmeta
116
182
  if @editmeta.nil?
117
183
  @editmeta = self.class.editmeta(self.jira_key)
@@ -119,6 +185,9 @@ module Jiralicious
119
185
  @editmeta
120
186
  end
121
187
 
188
+ ##
189
+ # Saves the current Issue but does not update itself.
190
+ #
122
191
  def save
123
192
  if loaded?
124
193
  self.class.update(@fields.format_for_update, self.jira_key)
@@ -127,7 +196,14 @@ module Jiralicious
127
196
  response = self.class.create(@fields.format_for_create)
128
197
  key = response.parsed_response['key']
129
198
  end
130
- load(self.class.find(key, {:reload => true}).parsed_response)
199
+ return key
200
+ end
201
+
202
+ ##
203
+ # Saves the current Issue and reloads to ensure it is upto date.
204
+ #
205
+ def save!
206
+ load(self.class.find(save, {:reload => true}).parsed_response)
131
207
  end
132
208
  end
133
209
  end
@@ -1,19 +1,38 @@
1
1
  # encoding: utf-8
2
2
  module Jiralicious
3
3
  class Issue
4
+ ##
5
+ # The Comment class retrieves and controls the functionality
6
+ # of Comments associated with an Issue.
7
+ #
4
8
  class Comment < Jiralicious::Base
5
-
9
+ # Related Issue Key
6
10
  attr_accessor :jira_key
7
11
 
12
+ ##
13
+ # Initialization Method
14
+ #
8
15
  def initialize(decoded_json = nil, default = nil, &blk)
9
16
  if (decoded_json != nil)
10
17
  properties_from_hash(decoded_json)
11
18
  super(decoded_json)
12
19
  parse!(decoded_json)
20
+ if self.respond_to?("comments")
21
+ if self.comments.is_a? Array
22
+ a = {}
23
+ self.comments.each do |comment|
24
+ a["_#{comment['id']}"] = Comment.new(comment)
25
+ end
26
+ self.comments = a
27
+ end
28
+ end
13
29
  end
14
30
  end
15
31
 
16
32
  class << self
33
+ ##
34
+ # Retrieves the Comments based on the Issue Key
35
+ #
17
36
  def find_by_key(key, options = {})
18
37
  response = fetch({:parent => parent_name, :parent_key => key})
19
38
  a = new(response)
@@ -21,6 +40,9 @@ module Jiralicious
21
40
  return a
22
41
  end
23
42
 
43
+ ##
44
+ # Retrieves the Comment based on the Issue Key and Comment ID
45
+ #
24
46
  def find_by_key_and_id(key, id, options = {})
25
47
  response = fetch({:parent => parent_name, :parent_key => key, :key => id})
26
48
  a = new(response)
@@ -28,32 +50,58 @@ module Jiralicious
28
50
  return a
29
51
  end
30
52
 
53
+ ##
54
+ # Adds a new Comment to the Issue
55
+ #
31
56
  def add(comment, key)
32
57
  fetch({:method => :post, :body => comment, :parent => parent_name, :parent_key => key})
33
58
  end
34
59
 
60
+ ##
61
+ # Updates a Comment based on Issue Key and Comment ID
62
+ #
35
63
  def edit(comment, key, id)
36
64
  fetch({:method => :put, :key => id, :body => comment, :parent => parent_name, :parent_key => key})
37
65
  end
38
66
 
67
+ ##
68
+ # Removes/Deletes the Comment from the Jira Issue. It is not recommended to delete comments however the functionality is provided.
69
+ # it is recommended to override this function to throw an error or warning
70
+ # to maintain data integrity in systems that do not allow deleting from a
71
+ # remote location.
72
+ #
39
73
  def remove(key, id)
40
74
  fetch({:method => :delete, :body_to_params => true, :key => id, :parent => parent_name, :parent_key => key})
41
75
 
42
76
  end
43
77
  end
44
78
 
79
+ ##
80
+ # Retrieves the Comment based on the loaded Issue and Comment ID
81
+ #
45
82
  def find_by_id(id, options = {})
46
83
  self.class.find_by_key_and_id(@jira_key, id)
47
84
  end
48
85
 
86
+ ##
87
+ # Adds a new Comment to the loaded Issue
88
+ #
49
89
  def add(comment)
50
90
  self.class.add(comment, @jira_key)
51
91
  end
52
92
 
93
+ ##
94
+ # Updates a Comment based on loaded Issue and Comment
95
+ #
53
96
  def edit(comment)
54
97
  self.class.edit(comment, @jira_key, self.id)
55
98
  end
56
99
 
100
+ ##
101
+ # Removes/Deletes the Comment from the Jira Issue. It is not recommended to delete comments;
102
+ # However, the functionality is provided. It is recommended to override this function to throw an error or
103
+ # warning to maintain data integrity in systems that do not allow deleting from a remote location.
104
+ #
57
105
  def remove(id = self.id)
58
106
  self.class.remove(@jira_key, id)
59
107
  end
@@ -1,30 +1,52 @@
1
1
  # encoding: utf-8
2
2
  module Jiralicious
3
3
  class Issue
4
+ ##
5
+ # The Fields class provides functionality to the Issue class that allows it to easily
6
+ # update or create issues. The class retains the original and the proposed information
7
+ # which could be used for cross validation prior to posting an update.
8
+ #
4
9
  class Fields
10
+ # The fields that will be updated or created
5
11
  attr_accessor :fields_update
12
+ # The current fields when a ticket was loaded
6
13
  attr_accessor :fields_current
7
14
 
15
+ ##
16
+ # Initialization Method
17
+ #
8
18
  def initialize(fc = nil)
9
19
  @fields_current = (fc == nil) ? Hash.new : fc
10
20
  @fields_update = Hash.new
11
21
  end
12
22
 
23
+ ##
24
+ # Returns the count of fields being updated.
25
+ #
13
26
  def count
14
27
  return @fields_update.count
15
28
  end
16
29
 
30
+ ##
31
+ # Returns the length of fields being updated.
32
+ #
17
33
  def length
18
34
  return @fields_update.length
19
35
  end
20
36
 
37
+ ##
38
+ # Adds a comment to the field list
39
+ #
21
40
  def add_comment(comment)
22
- if !(@fields_update['comment'].type == Array)
41
+ if !(@fields_update['comment'].is_a? Array)
23
42
  @fields_update['comment'] = Array.new
24
43
  end
25
44
  @fields_update['comment'].push({"add" => {"body" => comment}})
26
45
  end
27
46
 
47
+ ##
48
+ # Appends the current String with the provided value
49
+ #
28
50
  def append_s(field, value)
29
51
  if (@fields_update[field] == nil)
30
52
  @fields_update[field] = @fields_current[field] unless @fields_current.nil?
@@ -33,46 +55,75 @@ module Jiralicious
33
55
  @fields_update[field] += " " + value.to_s
34
56
  end
35
57
 
58
+ ##
59
+ # Appends the current Array with the provided value
60
+ #
36
61
  def append_a(field, value)
37
62
  @fields_update[field] = @fields_current[field] if (@fields_update[field] == nil)
38
63
  @fields_update[field] = Array.new if !(@fields_update[field].is_a? Array)
39
64
  if value.is_a? String
40
- @fields_update[field].push(value)
65
+ @fields_update[field].push(value) unless @fields_update[field].include? value
41
66
  else
42
- @fields_update[field] = @fields_update[field].concat(value)
67
+ @fields_update[field] |= value
43
68
  end
44
69
  end
45
70
 
71
+ ##
72
+ # Appends the current Hash with the provided value
73
+ #
46
74
  def append_h(field, hash)
47
75
  @fields_update[field] = @fields_current[field] if (@fields_update[field] == nil)
48
76
  @fields_update[field] = Hash.new if !(@fields_update[field].is_a? Hash)
49
77
  @fields_update[field].merge!(hash)
50
78
  end
51
79
 
80
+ ##
81
+ # Sets the field key with the provided value.
82
+ #
52
83
  def set(field, value)
53
84
  @fields_update[field] = value
54
85
  end
55
86
 
87
+ ##
88
+ # Sets the field with a name hash.
89
+ # This is necessary for some objects in Jira.
90
+ #
56
91
  def set_name(field, value)
57
92
  @fields_update[field] = {"name" => value}
58
93
  end
59
94
 
95
+ ##
96
+ # Sets the field with a id hash.
97
+ # This is necessary for some objects in Jira.
98
+ #
60
99
  def set_id(field, value)
61
100
  @fields_update[field] = {"id" => value}
62
101
  end
63
-
102
+ ##
103
+ # Fills the fields_current object with the provided Hash.
104
+ #
64
105
  def set_current(fc)
65
106
  @fields_current = fc if fc.type == Hash
66
107
  end
67
108
 
109
+ ##
110
+ # Returns the current fields object
111
+ #
68
112
  def current
69
113
  return @fields_current
70
114
  end
71
115
 
116
+ ##
117
+ # Returns the updated fields object
118
+ #
72
119
  def updated
73
120
  return @fields_update
74
121
  end
75
122
 
123
+ ##
124
+ # Formats the fields_update object correctly
125
+ # for Jira to perform an update request.
126
+ #
76
127
  def format_for_update
77
128
  up = Hash.new
78
129
  @fields_update.each do |k, v|
@@ -85,6 +136,10 @@ module Jiralicious
85
136
  return {"update" => up}
86
137
  end
87
138
 
139
+ ##
140
+ # Formats the fields_update object correctly
141
+ # for Jira to perform an create request.
142
+ #
88
143
  def format_for_create
89
144
  return {"fields" => @fields_update}
90
145
  end
@@ -1,31 +1,50 @@
1
- # To change this template, choose Tools | Templates
2
- # and open the template in the editor.
1
+ # encoding: utf-8
3
2
  module Jiralicious
4
3
  class Issue
4
+ ##
5
+ # The Transitions Class provides all of the functionality to retrieve,
6
+ # and use a transition associated with an Issue.
7
+ #
5
8
  class Transitions < Jiralicious::Base
6
9
 
10
+ # Contains the meta data to process a Transaction
7
11
  attr_accessor :meta
8
12
 
9
- def initialize(decoded_json, default = nil, &blk)
13
+ ##
14
+ # Initialization Method
15
+ #
16
+ def initialize(decoded_json = nil, default = nil, &blk)
10
17
  @loaded = false
11
18
  @meta = nil
12
- if decoded_json.is_a? Hash
13
- properties_from_hash(decoded_json)
14
- super(decoded_json)
15
- parse!(decoded_json)
16
- @loaded = true
17
- else
18
- self.class.property :jira_key
19
- self.jira_key = default
20
- decoded_json.each do |list|
21
- self.class.property :"id_#{list['id']}"
22
- self.merge!({"id_#{list['id']}" => self.class.new(list)})
19
+ if decoded_json.is_a? Array
20
+ if decoded_json.length == 1
21
+ decoded_json = decoded_json[0]
22
+ end
23
+ end
24
+ unless decoded_json.nil?
25
+ if decoded_json.is_a? String
26
+ self.class.property :jira_key
27
+ self.jira_key = decoded_json
28
+ elsif decoded_json.is_a? Hash
29
+ properties_from_hash(decoded_json)
30
+ super(decoded_json)
31
+ parse!(decoded_json)
32
+ @loaded = true
33
+ else
34
+ self.class.property :jira_key
35
+ self.jira_key = default
36
+ decoded_json.each do |list|
37
+ self.class.property :"id_#{list['id']}"
38
+ self.merge!({"id_#{list['id']}" => self.class.new(list)})
39
+ end
23
40
  end
24
41
  end
25
42
  end
26
43
 
27
44
  class << self
28
-
45
+ ##
46
+ # Retrieves the associated Transitions based on the Issue Key
47
+ #
29
48
  def find(key, options = {})
30
49
  response = fetch({:parent => parent_name, :parent_key => key})
31
50
  response.parsed_response['transitions'].each do |t|
@@ -35,13 +54,21 @@ module Jiralicious
35
54
  return a
36
55
  end
37
56
 
57
+ ##
58
+ # Retrieves the Transition based on the Issue Key and Transition ID
59
+ #
38
60
  def find_by_key_and_id(key, id, options = {})
39
- response = fetch({:key => id, :parent => parent_name, :parent_key => key})
40
- response.parsed_response['jira_key'] = key
61
+ response = fetch({:parent => parent_name, :parent_key => key, :body => {"transitionId" => id}, :body_to_params => true })
62
+ response.parsed_response['transitions'].each do |t|
63
+ t['jira_key'] = key
64
+ end
41
65
  a = new(response.parsed_response['transitions'])
42
66
  return a
43
67
  end
44
68
 
69
+ ##
70
+ # Processes the Transition based on the provided options
71
+ #
45
72
  def go(key, id, options = {})
46
73
  transition = {"transition" => {"id" => id}}
47
74
  if options[:comment].is_a? String
@@ -59,6 +86,10 @@ module Jiralicious
59
86
  fetch({:method => :post, :parent => parent_name, :parent_key => key, :body => transition})
60
87
  end
61
88
 
89
+ ##
90
+ # Retrieves the meta data for the Transition based on the
91
+ # options, Issue Key and Transition ID provided.
92
+ #
62
93
  def meta(key, id, options = {})
63
94
  response = fetch({:method => :get, :parent => parent_name, :parent_key => key, :body_to_params => true,
64
95
  :body => {"transitionId" => id, "expand" => "transitions.fields"}})
@@ -72,14 +103,24 @@ module Jiralicious
72
103
  alias :find_all :find
73
104
  end
74
105
 
106
+ ##
107
+ # Retrieves the associated Transitions based on the Issue Key
108
+ #
75
109
  def all
76
110
  self.class.all(self.jira_key) if self.jira_key
77
111
  end
78
112
 
113
+ ##
114
+ # Processes the Transition based on the provided options
115
+ #
79
116
  def go(options = {})
80
117
  self.class.go(self.jira_key, self.id, options)
81
118
  end
82
119
 
120
+ ##
121
+ # Retrieves the meta data for the Transition based on the
122
+ # options, Issue Key and Transition ID provided.
123
+ #
83
124
  def meta
84
125
  if @meta.nil?
85
126
  l = self.class.meta(self.jira_key, self.id, {:return => true})
@@ -1,11 +1,18 @@
1
- # To change this template, choose Tools | Templates
2
- # and open the template in the editor.
1
+ # encoding: utf-8
3
2
  module Jiralicious
4
3
  class Issue
4
+ ##
5
+ # The Watchers class is used to manage the watchers on an issue.
6
+ #
5
7
  class Watchers < Jiralicious::Base
6
-
8
+ ##
9
+ # Holds the Issue Key
10
+ #
7
11
  attr_accessor :jira_key
8
12
 
13
+ ##
14
+ # Initialization Method
15
+ #
9
16
  def initialize(decoded_json = nil, default = nil, &blk)
10
17
  if (decoded_json != nil)
11
18
  properties_from_hash(decoded_json)
@@ -15,6 +22,9 @@ module Jiralicious
15
22
  end
16
23
 
17
24
  class << self
25
+ ##
26
+ # Finds all watchers based on the provided Issue Key
27
+ #
18
28
  def find_by_key(key)
19
29
  response = fetch({:parent => parent_name, :parent_key => key})
20
30
  a = new(response)
@@ -22,23 +32,38 @@ module Jiralicious
22
32
  return a
23
33
  end
24
34
 
35
+ ##
36
+ # Adds a new Watcher to the Issue
37
+ #
25
38
  def add(name, key)
26
39
  fetch({:method => :post, :body => name, :body_override => true, :parent => parent_name, :parent_key => key})
27
40
  end
28
41
 
42
+ ##
43
+ # Removes/Deletes a Watcher from the Issue
44
+ #
29
45
  def remove(name, key)
30
46
  fetch({:method => :delete, :body_to_params => true, :body => {:username => name}, :parent => parent_name, :parent_key => key})
31
47
  end
32
48
  end
33
49
 
50
+ ##
51
+ # Finds all watchers based on the provided Issue Key
52
+ #
34
53
  def find
35
54
  self.class.find_by_key(@jira_key)
36
55
  end
37
56
 
57
+ ##
58
+ # Adds a new Watcher to the Issue
59
+ #
38
60
  def add(name)
39
61
  self.class.add(name, @jira_key)
40
62
  end
41
63
 
64
+ ##
65
+ # Removes/Deletes a Watcher from the Issue
66
+ #
42
67
  def remove(name)
43
68
  self.class.remove(name, @jira_key)
44
69
  end
@@ -1,7 +1,14 @@
1
1
  # encoding: utf-8
2
2
  module Jiralicious
3
3
  module Parsers
4
+ ##
5
+ # The FieldParser module is an extention that assists in
6
+ # managing hash parsing and implementation.
7
+ #
4
8
  module FieldParser
9
+ ##
10
+ # Parses an Array or Hash into the current class object.
11
+ #
5
12
  def parse!(fields)
6
13
  unless fields.is_a?(Hash)
7
14
  raise ArgumentError
@@ -32,12 +39,18 @@ module Jiralicious
32
39
 
33
40
  private
34
41
 
42
+ ##
43
+ # Normalizes key names
44
+ #
35
45
  def normalize(name)
36
46
  name.gsub(/(\w+)([A-Z].*)/, '\1_\2').
37
47
  gsub(/\W/, "_").
38
48
  downcase
39
49
  end
40
50
 
51
+ ##
52
+ # Converts Array or Hash to a Mash object
53
+ #
41
54
  def mashify(data)
42
55
  if data.is_a?(Array)
43
56
  data.map { |d| mashify(d) }
@@ -1,11 +1,14 @@
1
- # To change this template, choose Tools | Templates
2
- # and open the template in the editor.
1
+ # encoding: utf-8
3
2
  module Jiralicious
3
+ ##
4
+ # The Project class rolls up the basic functionality for
5
+ # managing Projects within Jira through the Rest API.
6
+ #
4
7
  class Project < Jiralicious::Base
5
-
6
- attr_accessor :issues
7
8
 
8
- ### Initialization ###
9
+ ##
10
+ # Initialization Method
11
+ #
9
12
  def initialize(decoded_json, default = nil, &blk)
10
13
  @loaded = false
11
14
  if decoded_json.is_a? Hash
@@ -22,6 +25,11 @@ module Jiralicious
22
25
  end
23
26
 
24
27
  class << self
28
+ ##
29
+ # Returns a list of issues within the project. The issue list is limited
30
+ # to only return the issue ID and KEY values to minimize the amount of
31
+ # data being returned This is used in lazy loading methodology.
32
+ #
25
33
  def issue_list(key)
26
34
  response = Jiralicious.search("project=#{key}", {:fields => ["id", "key"]})
27
35
  i_out = Issue.new
@@ -34,6 +42,11 @@ module Jiralicious
34
42
  end
35
43
  end
36
44
 
45
+ ##
46
+ # Issues loads the issue list into the current Project.
47
+ # It also acts as a reference for lazy loading of issues.
48
+ #
49
+ attr_accessor :issues
37
50
  def issues
38
51
  if @issues == nil
39
52
  @issues = self.class.issue_list(self.key)
@@ -1,5 +1,9 @@
1
1
  # encoding: utf-8
2
2
  module Jiralicious
3
+ ##
4
+ # Provides the interface to access the JQL search functionality.
5
+ # Uses the same syntax as Rest interface for JQL criteria.
6
+ #
3
7
  def search(jql, options = {})
4
8
  options[:start_at] ||= 0
5
9
  options[:max_results] ||= 50
@@ -1,19 +1,36 @@
1
1
  module Jiralicious
2
+ ##
3
+ # The SearchResult class organizes the response from the Jira API
4
+ # In a way that is easily parsable into Issues.
5
+ #
2
6
  class SearchResult
7
+ # Attributes available for usage regarding the current position in the list
3
8
  attr_reader :offset, :num_results
4
9
 
10
+ ##
11
+ # Initialization Method
12
+ #
13
+ # Parses the hash into attributes.
14
+ #
5
15
  def initialize(search_data)
6
16
  @issues = search_data["issues"]
7
17
  @offset = search_data["startAt"]
8
18
  @num_results = search_data["total"]
9
19
  end
10
20
 
21
+ ##
22
+ # Loads the different issues through the map. This is not recommended for large objects
23
+ # as it can be troublesome to load multiple Issues to locate the desired one. If the user needs to have all of the information available on each issue this method works perfectly for that process.
24
+ #
11
25
  def issues
12
26
  @issues.map do |issue|
13
27
  Jiralicious::Issue.find(issue["key"])
14
28
  end
15
29
  end
16
30
 
31
+ ##
32
+ # Returns the Issues attribute without loading the extra information. Ideal for a quick scan of the Hash prior to selecting the correct Issue. This method is also used in the lazy loading methodology.
33
+ #
17
34
  def issues_raw
18
35
  @issues
19
36
  end
@@ -2,12 +2,21 @@
2
2
  require 'jiralicious/configuration'
3
3
 
4
4
  module Jiralicious
5
+ ##
6
+ # The Session class handles the interactions with the Jira Rest API
7
+ # Through the HTTParty gem.
8
+ #
5
9
  class Session
6
10
  include HTTParty
7
11
 
12
+ # Sets the default format to JSON for send and return
8
13
  format :json
14
+ # Sets the default headers to application/json for send and return
9
15
  headers 'Content-Type' => 'application/json'
10
16
 
17
+ ##
18
+ # Main access method to request data from the Jira API
19
+ #
11
20
  def request(method, *options)
12
21
  if options.last.is_a?(Hash) && options.last[:handler]
13
22
  response_handler = options.last.delete(:handler)
@@ -25,6 +34,10 @@ module Jiralicious
25
34
 
26
35
  private
27
36
 
37
+ ##
38
+ # Configures the default handler. This can be overridden in
39
+ # the child class to provide additional error handling.
40
+ #
28
41
  def handler
29
42
  Proc.new do |response|
30
43
  case response
@@ -1,3 +1,4 @@
1
1
  module Jiralicious
2
- VERSION = "0.2.0"
2
+ # Current Jiralicious Version
3
+ VERSION = "0.2.1"
3
4
  end
data/spec/comment_spec.rb CHANGED
@@ -33,14 +33,14 @@ describe Jiralicious, "search" do
33
33
  :status => "204")
34
34
  end
35
35
 
36
- it "finds by isusse key" do
36
+ it "finds by issue key" do
37
37
  comments = Jiralicious::Issue::Comment.find_by_key("EX-1")
38
38
  comments.should be_instance_of(Jiralicious::Issue::Comment)
39
39
  comments.comments.count.should == 1
40
- comments.comments[0]['id'].should == "10000"
40
+ comments.comments.first[1].id.should == "10000"
41
41
  end
42
42
 
43
- it "finds by isusse key and comment id" do
43
+ it "finds by issue key and comment id" do
44
44
  comments = Jiralicious::Issue::Comment.find_by_key_and_id("EX-1", "10000")
45
45
  comments.should be_instance_of(Jiralicious::Issue::Comment)
46
46
  comments.id.should == "10000"
data/spec/issue_spec.rb CHANGED
@@ -134,7 +134,7 @@ describe Jiralicious::Issue, "Managing Issues" do
134
134
  issue.fields.set("labels", ["new_label_p"])
135
135
  issue.fields.set("environment", "example of environment")
136
136
  issue.fields.set("description", "example of the description extending")
137
- issue.save
137
+ issue.save!
138
138
  issue.jira_key.should == 'EX-2'
139
139
  issue.comments.comments.count.should == 0
140
140
  issue.watchers.watchers.count.should == 1
@@ -142,7 +142,7 @@ describe Jiralicious::Issue, "Managing Issues" do
142
142
 
143
143
  it "updates a new issue" do
144
144
  issue = Jiralicious::Issue.find("EX-3")
145
- issue.fields.append_a("labels", "test_label")
145
+ issue.fields.append_a("labels", ["test_label"])
146
146
  issue.fields.append_s("description", " updated description ")
147
147
  issue.save
148
148
  issue.jira_key.should == 'EX-3'
@@ -24,7 +24,7 @@ describe Jiralicious, "search" do
24
24
  :status => "204")
25
25
  end
26
26
 
27
- it "finds by isusse key" do
27
+ it "finds by issue key" do
28
28
  watchers = Jiralicious::Issue::Watchers.find_by_key("EX-1")
29
29
  watchers.should be_instance_of(Jiralicious::Issue::Watchers)
30
30
  watchers.watchers.count.should == 1
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jiralicious
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-29 00:00:00.000000000 Z
12
+ date: 2013-06-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: crack