jiralicious 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +3 -0
- data/jiralicious.gemspec +0 -2
- data/lib/jiralicious.rb +4 -0
- data/lib/jiralicious/avatar.rb +101 -0
- data/lib/jiralicious/base.rb +53 -15
- data/lib/jiralicious/configuration.rb +30 -4
- data/lib/jiralicious/custom_field_option.rb +7 -3
- data/lib/jiralicious/errors.rb +10 -0
- data/lib/jiralicious/field.rb +23 -12
- data/lib/jiralicious/issue.rb +69 -11
- data/lib/jiralicious/issue/comment.rb +54 -12
- data/lib/jiralicious/issue/fields.rb +44 -3
- data/lib/jiralicious/issue/transitions.rb +42 -11
- data/lib/jiralicious/issue/watchers.rb +19 -2
- data/lib/jiralicious/parsers/field_parser.rb +12 -0
- data/lib/jiralicious/project.rb +7 -1
- data/lib/jiralicious/project/avatar.rb +126 -0
- data/lib/jiralicious/search.rb +9 -0
- data/lib/jiralicious/search_result.rb +15 -7
- data/lib/jiralicious/session.rb +5 -0
- data/lib/jiralicious/user.rb +154 -0
- data/lib/jiralicious/user/avatar.rb +130 -0
- data/lib/jiralicious/version.rb +1 -1
- data/spec/avatar_spec.rb +50 -0
- data/spec/basic_session_spec.rb +4 -0
- data/spec/comment_spec.rb +2 -2
- data/spec/fixtures/avatar.json +7 -0
- data/spec/fixtures/avatar_custom.json +16 -0
- data/spec/fixtures/avatar_list.json +16 -0
- data/spec/fixtures/avatar_temp.json +7 -0
- data/spec/fixtures/avatar_test.png +0 -0
- data/spec/fixtures/user.json +27 -0
- data/spec/fixtures/user_array.json +26 -0
- data/spec/fixtures/user_picker.json +18 -0
- data/spec/issue_spec.rb +10 -9
- data/spec/project_avatar_spec.rb +66 -0
- data/spec/project_spec.rb +2 -2
- data/spec/search_spec.rb +2 -1
- data/spec/support/http.rb +24 -0
- data/spec/user_avatar_spec.rb +66 -0
- data/spec/user_spec.rb +79 -0
- data/spec/watchers_spec.rb +2 -2
- metadata +30 -18
@@ -2,7 +2,8 @@
|
|
2
2
|
module Jiralicious
|
3
3
|
class Issue
|
4
4
|
##
|
5
|
-
# The Watchers class is used to manage the
|
5
|
+
# The Watchers class is used to manage the
|
6
|
+
# watchers on an issue.
|
6
7
|
#
|
7
8
|
class Watchers < Jiralicious::Base
|
8
9
|
##
|
@@ -13,7 +14,7 @@ module Jiralicious
|
|
13
14
|
##
|
14
15
|
# Initialization Method
|
15
16
|
#
|
16
|
-
def initialize(decoded_json = nil
|
17
|
+
def initialize(decoded_json = nil)
|
17
18
|
if (decoded_json != nil)
|
18
19
|
properties_from_hash(decoded_json)
|
19
20
|
super(decoded_json)
|
@@ -25,6 +26,9 @@ module Jiralicious
|
|
25
26
|
##
|
26
27
|
# Finds all watchers based on the provided Issue Key
|
27
28
|
#
|
29
|
+
# [Arguments]
|
30
|
+
# :key (required) issue key to find
|
31
|
+
#
|
28
32
|
def find_by_key(key)
|
29
33
|
response = fetch({:parent => parent_name, :parent_key => key})
|
30
34
|
a = new(response)
|
@@ -35,6 +39,11 @@ module Jiralicious
|
|
35
39
|
##
|
36
40
|
# Adds a new Watcher to the Issue
|
37
41
|
#
|
42
|
+
# [Arguments]
|
43
|
+
# :name (required) name of the watcher
|
44
|
+
#
|
45
|
+
# :key (required) issue key
|
46
|
+
#
|
38
47
|
def add(name, key)
|
39
48
|
fetch({:method => :post, :body => name, :body_override => true, :parent => parent_name, :parent_key => key})
|
40
49
|
end
|
@@ -42,6 +51,11 @@ module Jiralicious
|
|
42
51
|
##
|
43
52
|
# Removes/Deletes a Watcher from the Issue
|
44
53
|
#
|
54
|
+
# [Arguments]
|
55
|
+
# :name (required) name of the watcher
|
56
|
+
#
|
57
|
+
# :key (required) issue key
|
58
|
+
#
|
45
59
|
def remove(name, key)
|
46
60
|
fetch({:method => :delete, :body_to_params => true, :body => {:username => name}, :parent => parent_name, :parent_key => key})
|
47
61
|
end
|
@@ -57,6 +71,9 @@ module Jiralicious
|
|
57
71
|
##
|
58
72
|
# Adds a new Watcher to the Issue
|
59
73
|
#
|
74
|
+
# [Arguments]
|
75
|
+
# :name (required) name of the watcher
|
76
|
+
#
|
60
77
|
def add(name)
|
61
78
|
self.class.add(name, @jira_key)
|
62
79
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module Jiralicious
|
3
|
+
##
|
4
|
+
# Parsing module contains all of the parser functionality
|
5
|
+
#
|
3
6
|
module Parsers
|
4
7
|
##
|
5
8
|
# The FieldParser module is an extention that assists in
|
@@ -9,6 +12,9 @@ module Jiralicious
|
|
9
12
|
##
|
10
13
|
# Parses an Array or Hash into the current class object.
|
11
14
|
#
|
15
|
+
# [Arguments]
|
16
|
+
# :fields (required) fields to be parsed
|
17
|
+
#
|
12
18
|
def parse!(fields)
|
13
19
|
unless fields.is_a?(Hash)
|
14
20
|
raise ArgumentError
|
@@ -42,6 +48,9 @@ module Jiralicious
|
|
42
48
|
##
|
43
49
|
# Normalizes key names
|
44
50
|
#
|
51
|
+
# [Arguments]
|
52
|
+
# :name (required) name to be normalized
|
53
|
+
#
|
45
54
|
def normalize(name)
|
46
55
|
name.gsub(/(\w+)([A-Z].*)/, '\1_\2').
|
47
56
|
gsub(/\W/, "_").
|
@@ -51,6 +60,9 @@ module Jiralicious
|
|
51
60
|
##
|
52
61
|
# Converts Array or Hash to a Mash object
|
53
62
|
#
|
63
|
+
# [Arguments]
|
64
|
+
# :data (required) data be be mashified
|
65
|
+
#
|
54
66
|
def mashify(data)
|
55
67
|
if data.is_a?(Array)
|
56
68
|
data.map { |d| mashify(d) }
|
data/lib/jiralicious/project.rb
CHANGED
@@ -9,7 +9,10 @@ module Jiralicious
|
|
9
9
|
##
|
10
10
|
# Initialization Method
|
11
11
|
#
|
12
|
-
|
12
|
+
# [Arguments]
|
13
|
+
# :decoded_json (optional) rubyized json object
|
14
|
+
#
|
15
|
+
def initialize(decoded_json)
|
13
16
|
@loaded = false
|
14
17
|
if decoded_json.is_a? Hash
|
15
18
|
properties_from_hash(decoded_json)
|
@@ -30,6 +33,9 @@ module Jiralicious
|
|
30
33
|
# to only return the issue ID and KEY values to minimize the amount of
|
31
34
|
# data being returned This is used in lazy loading methodology.
|
32
35
|
#
|
36
|
+
# [Arguments]
|
37
|
+
# :key (required) project key
|
38
|
+
#
|
33
39
|
def issue_list(key)
|
34
40
|
response = Jiralicious.search("project=#{key}", {:fields => ["id", "key"]})
|
35
41
|
i_out = Issue.new
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Jiralicious
|
3
|
+
class Project
|
4
|
+
##
|
5
|
+
# Avatars in the Project class.
|
6
|
+
#
|
7
|
+
class Avatar < Jiralicious::Base
|
8
|
+
|
9
|
+
##
|
10
|
+
# Initialization Method
|
11
|
+
#
|
12
|
+
# [Arguments]
|
13
|
+
# :decoded_json (optional) decoded json object
|
14
|
+
#
|
15
|
+
def initialize(decoded_json = nil)
|
16
|
+
@loaded = false
|
17
|
+
if !decoded_json.nil?
|
18
|
+
if decoded_json.is_a? Hash
|
19
|
+
decoded_json = properties_from_hash(decoded_json)
|
20
|
+
super(decoded_json)
|
21
|
+
parse!(decoded_json)
|
22
|
+
self.each do |k, v|
|
23
|
+
if v.is_a? Hash
|
24
|
+
self[k] = self.class.new(v)
|
25
|
+
elsif v.is_a? Array
|
26
|
+
v.each_index do |i|
|
27
|
+
if v[i].is_a? Hash
|
28
|
+
v[i] = self.class.new(v[i])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
self[k] = v
|
32
|
+
end
|
33
|
+
end
|
34
|
+
@loaded = true
|
35
|
+
else
|
36
|
+
i = 0;
|
37
|
+
decoded_json.each do |list|
|
38
|
+
if !list['id'].nil?
|
39
|
+
if numeric? list['id']
|
40
|
+
id = :"id_#{list['id']}"
|
41
|
+
else
|
42
|
+
id = :"#{list['id']}"
|
43
|
+
end
|
44
|
+
else
|
45
|
+
id = :"_#{i}"
|
46
|
+
i += 1
|
47
|
+
end
|
48
|
+
self.class.property id
|
49
|
+
self[id] = self.class.new(list)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class << self
|
56
|
+
##
|
57
|
+
# Converts the temporary avatar to a real avatar
|
58
|
+
#
|
59
|
+
# [Arguments]
|
60
|
+
# :key (required) project key
|
61
|
+
#
|
62
|
+
# :cropperWidth (optional) width of the avatar
|
63
|
+
#
|
64
|
+
# :cropperOffsetX (optional) X offset on image
|
65
|
+
#
|
66
|
+
# :cropperOffsetY (optional) Y offset on image
|
67
|
+
#
|
68
|
+
# :needsCropping (optional) boolean if it needs cropping
|
69
|
+
#
|
70
|
+
def post(key, options = {})
|
71
|
+
response = fetch({:method => :post, :parent => true, :parent_key => key, :body => options})
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Update Avatar information
|
76
|
+
#
|
77
|
+
# [Arguments]
|
78
|
+
# :key (required) project key
|
79
|
+
#
|
80
|
+
# :options (optional) not documented
|
81
|
+
#
|
82
|
+
def put(key, options = {})
|
83
|
+
response = fetch({:method => :put, :parent => true, :parent_key => key, :body => options})
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Creates tempoary avatar
|
88
|
+
#
|
89
|
+
# [Arguments]
|
90
|
+
# :key (required) project key
|
91
|
+
#
|
92
|
+
# :filename (required) file to upload
|
93
|
+
#
|
94
|
+
# :size (required) size of the file
|
95
|
+
#
|
96
|
+
def temporary(key, options = {})
|
97
|
+
response = fetch({:method => :post, :parent => true, :parent_key => key, :key => 'temporary', :body => options})
|
98
|
+
return self.new(response.parsed_response)
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Deletes or removes the avatar from the project
|
103
|
+
#
|
104
|
+
# [Arguments]
|
105
|
+
# :key (required) project key
|
106
|
+
#
|
107
|
+
# :id (required) avatar id
|
108
|
+
#
|
109
|
+
def remove(key, id)
|
110
|
+
response = fetch({:method => :delete, :body_to_params => true, :parent => true, :parent_key => key, :key => "#{id}"})
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Gets a list of available avatars
|
115
|
+
#
|
116
|
+
# [Arguments]
|
117
|
+
# :key (required) project key
|
118
|
+
#
|
119
|
+
def avatars(key, options = {})
|
120
|
+
response = fetch({:method => :get, :url => "#{Jiralicious.rest_path}/#{parent_name}/#{key}/#{endpoint_name}s/", :body_to_params => true, :body => options})
|
121
|
+
return self.new(response.parsed_response)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/jiralicious/search.rb
CHANGED
@@ -4,6 +4,15 @@ module Jiralicious
|
|
4
4
|
# Provides the interface to access the JQL search functionality.
|
5
5
|
# Uses the same syntax as Rest interface for JQL criteria.
|
6
6
|
#
|
7
|
+
# [Arguments]
|
8
|
+
# :jql (required) JQL string
|
9
|
+
#
|
10
|
+
# :start_at (optional) offset to start at
|
11
|
+
#
|
12
|
+
# :max_results (optional) maximum number to return
|
13
|
+
#
|
14
|
+
# :fields (optional) field options
|
15
|
+
#
|
7
16
|
def search(jql, options = {})
|
8
17
|
options[:start_at] ||= 0
|
9
18
|
options[:max_results] ||= 50
|
@@ -12,25 +12,33 @@ module Jiralicious
|
|
12
12
|
#
|
13
13
|
# Parses the hash into attributes.
|
14
14
|
#
|
15
|
+
# [Arguments]
|
16
|
+
# :search_data (required) hash data to be parsed
|
17
|
+
#
|
15
18
|
def initialize(search_data)
|
16
19
|
@issues = search_data["issues"]
|
17
20
|
@offset = search_data["startAt"]
|
18
21
|
@num_results = search_data["total"]
|
19
22
|
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
##
|
25
|
+
# Loads the different issues through the map. This is not recommended
|
26
|
+
# for large objects as it can be troublesome to load multiple Issues
|
27
|
+
# to locate the desired one. If the user needs to have all of the
|
28
|
+
# information available on each issue this method works perfectly for
|
29
|
+
# that process.
|
30
|
+
#
|
25
31
|
def issues
|
26
32
|
@issues.map do |issue|
|
27
33
|
Jiralicious::Issue.find(issue["key"])
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
##
|
38
|
+
# Returns the Issues attribute without loading the extra information.
|
39
|
+
# Ideal for a quick scan of the Hash prior to selecting the correct
|
40
|
+
# Issue. This method is also used in the lazy loading methodology.
|
41
|
+
#
|
34
42
|
def issues_raw
|
35
43
|
@issues
|
36
44
|
end
|
data/lib/jiralicious/session.rb
CHANGED
@@ -17,6 +17,11 @@ module Jiralicious
|
|
17
17
|
##
|
18
18
|
# Main access method to request data from the Jira API
|
19
19
|
#
|
20
|
+
# [Arguments]
|
21
|
+
# :method (required) http method type
|
22
|
+
#
|
23
|
+
# :options (required) request specific options
|
24
|
+
#
|
20
25
|
def request(method, *options)
|
21
26
|
if options.last.is_a?(Hash) && options.last[:handler]
|
22
27
|
response_handler = options.last.delete(:handler)
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Jiralicious
|
3
|
+
##
|
4
|
+
# The User class rolls up the functionality of user management.
|
5
|
+
# This class contains methods to manage Users from Ruby via the
|
6
|
+
# API.
|
7
|
+
#
|
8
|
+
class User < Jiralicious::Base
|
9
|
+
|
10
|
+
##
|
11
|
+
# Initialization Method
|
12
|
+
#
|
13
|
+
# [Arguments]
|
14
|
+
# :decoded_json (optional) rubyized json object
|
15
|
+
#
|
16
|
+
def initialize(decoded_json = nil)
|
17
|
+
@loaded = false
|
18
|
+
if !decoded_json.nil?
|
19
|
+
if decoded_json.is_a? Hash
|
20
|
+
decoded_json = properties_from_hash(decoded_json)
|
21
|
+
super(decoded_json)
|
22
|
+
parse!(decoded_json)
|
23
|
+
self.each do |k, v|
|
24
|
+
if v.is_a? Hash
|
25
|
+
self[k] = self.class.new(v)
|
26
|
+
elsif v.is_a? Array
|
27
|
+
v.each_index do |i|
|
28
|
+
if v[i].is_a? Hash
|
29
|
+
v[i] = self.class.new(v[i])
|
30
|
+
end
|
31
|
+
end
|
32
|
+
self[k] = v
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@loaded = true
|
36
|
+
else
|
37
|
+
i = 0;
|
38
|
+
decoded_json.each do |list|
|
39
|
+
if !list['id'].nil?
|
40
|
+
if numeric? list['id']
|
41
|
+
id = :"id_#{list['id']}"
|
42
|
+
else
|
43
|
+
id = :"#{list['id']}"
|
44
|
+
end
|
45
|
+
else
|
46
|
+
id = :"_#{i}"
|
47
|
+
i += 1
|
48
|
+
end
|
49
|
+
self.class.property id
|
50
|
+
self[id] = self.class.new(list)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class << self
|
57
|
+
##
|
58
|
+
# Retrieves the user by UserName.
|
59
|
+
#
|
60
|
+
# A valid request will return the user details.
|
61
|
+
# An invalid request will throw an error.
|
62
|
+
#
|
63
|
+
# [Arguments]
|
64
|
+
# :username (required) Must be correct username, no partials
|
65
|
+
#
|
66
|
+
def find(username)
|
67
|
+
response = fetch({:url => "#{Jiralicious.rest_path}/#{endpoint_name}", :method => :get, :body_to_params => true, :body => {:username => username}})
|
68
|
+
return self.new(response.parsed_response)
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Returns a list of users matching the criteria
|
73
|
+
#
|
74
|
+
# [Arguments]
|
75
|
+
# :projectKey (required) Should be upper case
|
76
|
+
#
|
77
|
+
# :username (optional) Must be correct username, no partials
|
78
|
+
#
|
79
|
+
# :startAt (optional) Integer
|
80
|
+
#
|
81
|
+
# :maxResults (optional) Integer
|
82
|
+
#
|
83
|
+
def assignable_multiProjectSearch(projectKeys, options = {})
|
84
|
+
options.merge!({:projectKeys=>projectKeys.upcase})
|
85
|
+
response = fetch({:method => :get, :key => "assignable/multiProjectSearch", :body_to_params => true, :body => options})
|
86
|
+
return self.new(response.parsed_response)
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
# Returns a list of users matching the criteria
|
91
|
+
#
|
92
|
+
# [Arguments]
|
93
|
+
# :project (required) Should be upper case
|
94
|
+
#
|
95
|
+
# OR
|
96
|
+
#
|
97
|
+
# :issueKey (required) Should be upper case
|
98
|
+
#
|
99
|
+
# :username (optional) Must be correct username,
|
100
|
+
# no partials, cannot be by itself
|
101
|
+
#
|
102
|
+
# :startAt (optional) Integer
|
103
|
+
#
|
104
|
+
# :maxResults (optional) Integer
|
105
|
+
#
|
106
|
+
# :ActionDescriptorId (optional) Integer
|
107
|
+
#
|
108
|
+
def assignable_search(options = {})
|
109
|
+
options[:project] = options[:project].upcase unless options[:project].nil?
|
110
|
+
options[:issueKey] = options[:issueKey].upcase unless options[:issueKey].nil?
|
111
|
+
response = fetch({:method => :get, :key => "assignable/search", :body_to_params => true, :body => options})
|
112
|
+
return self.new(response.parsed_response)
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Uses the user picker to find specified users
|
117
|
+
#
|
118
|
+
# [Arguments]
|
119
|
+
# :query (required) Name of user or username part or full
|
120
|
+
#
|
121
|
+
# :maxResults (optional) Integer
|
122
|
+
#
|
123
|
+
# :showAvatar (optional) Boolean, default false
|
124
|
+
#
|
125
|
+
# :exclude (optional) Users to exclude
|
126
|
+
#
|
127
|
+
def picker(query, options ={})
|
128
|
+
options.merge!({:query => query})
|
129
|
+
response = fetch({:method => :get, :key => "picker", :body_to_params => true, :body => options})
|
130
|
+
return self.new(response.parsed_response)
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Uses the user search to find specified users by username
|
135
|
+
#
|
136
|
+
# [Arguments]
|
137
|
+
# :username (required) Name of user or username part or full
|
138
|
+
#
|
139
|
+
# :startAt (optional) Integer
|
140
|
+
#
|
141
|
+
# :maxResults (optional) Integer
|
142
|
+
#
|
143
|
+
# :includeActive (optional) Boolean, default true
|
144
|
+
#
|
145
|
+
# :includeInactive (optional) Boolean, default true
|
146
|
+
#
|
147
|
+
def search(username, options ={})
|
148
|
+
options.merge!({:username => username})
|
149
|
+
response = fetch({:method => :get, :key => "search", :body_to_params => true, :body => options})
|
150
|
+
return self.new(response.parsed_response)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|