jirarest2 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data.tar.gz.sig +0 -0
- data/History.txt +19 -0
- data/Manifest.txt +4 -2
- data/README.txt +1 -1
- data/Rakefile +1 -0
- data/bin/create_issue.rb +3 -275
- data/bin/jira_create_issue.rb +366 -0
- data/lib/connect.rb +21 -24
- data/lib/credentials.rb +7 -12
- data/lib/exceptions.rb +1 -3
- data/lib/issue.rb +46 -58
- data/lib/jirarest2.rb +1 -1
- data/lib/jirarest2/result.rb +34 -30
- data/lib/madbitconfig.rb +82 -0
- data/lib/services.rb +12 -17
- data/lib/services/issuelink.rb +21 -15
- data/lib/services/issuelinktype.rb +17 -17
- data/lib/services/watcher.rb +15 -15
- data/test/data/test.config.data +3 -0
- data/test/test_madbitconfig.rb +33 -0
- metadata +30 -16
- metadata.gz.sig +0 -0
- data/lib/config.rb +0 -55
- data/lib/issuelink.rb +0 -74
data/lib/connect.rb
CHANGED
@@ -22,14 +22,12 @@ require 'jirarest2/result'
|
|
22
22
|
require "pp"
|
23
23
|
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
=end
|
25
|
+
|
26
|
+
# A Connect object encasulates the connection to jira via REST. It takes an Credentials object and returns a Jirarest2::Result object or an exception if something went wrong.
|
28
27
|
class Connect
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
=end
|
29
|
+
# Create an instance of Connect.
|
30
|
+
# @param [Credentials] credentials
|
33
31
|
def initialize(credentials)
|
34
32
|
@pass = credentials.password
|
35
33
|
@user = credentials.username
|
@@ -37,12 +35,12 @@ class Connect
|
|
37
35
|
end
|
38
36
|
|
39
37
|
|
40
|
-
|
41
|
-
Execute the request
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
38
|
+
|
39
|
+
# Execute the request
|
40
|
+
# @param [String, "Get", "Post", "Delete", "Put"] operation HTTP method: GET, POST, DELETE, PUT
|
41
|
+
# @param [String] uritail The last part of the REST URI
|
42
|
+
# @param [Hash] data Data to be sent.
|
43
|
+
# @return [Jirarest2::Result]
|
46
44
|
def execute(operation,uritail,data)
|
47
45
|
uri = nil
|
48
46
|
uri = URI(@CONNECTURL+uritail)
|
@@ -85,9 +83,9 @@ class Connect
|
|
85
83
|
return Jirarest2::Result.new(result)
|
86
84
|
end # execute
|
87
85
|
|
88
|
-
|
89
|
-
Is the rest API really at the destination we think it is?
|
90
|
-
|
86
|
+
|
87
|
+
# Is the rest API really at the destination we think it is?
|
88
|
+
# @return [Boolean]
|
91
89
|
def check_uri
|
92
90
|
begin
|
93
91
|
begin
|
@@ -98,9 +96,9 @@ class Connect
|
|
98
96
|
end
|
99
97
|
end
|
100
98
|
|
101
|
-
|
102
|
-
|
103
|
-
|
99
|
+
# Try to be nice. Parse the URI and see if you can find a pattern to the problem
|
100
|
+
# @param [String] url
|
101
|
+
# @return [String] a fixed URL
|
104
102
|
def heal_uri(url = @CONNECTURL)
|
105
103
|
splitURI = URI.split(url) # [Scheme,Userinfo,Host,Port,Registry,Path,Opaque,Query,Fragment]
|
106
104
|
splitURI[5].gsub!(/^(.*)2$/,'\12/')
|
@@ -115,12 +113,10 @@ class Connect
|
|
115
113
|
end
|
116
114
|
return url
|
117
115
|
end
|
118
|
-
end # class
|
119
116
|
|
120
|
-
|
121
|
-
try to fix the
|
122
|
-
|
123
|
-
public
|
117
|
+
|
118
|
+
# try to fix the connecturl of this instance
|
119
|
+
# @return [String,Jirarest2::CouldNotHealURIError] Fixed URL or Exception
|
124
120
|
def heal_uri!
|
125
121
|
if ! check_uri then
|
126
122
|
@CONNECTURL = heal_uri(@CONNECTURL)
|
@@ -132,8 +128,9 @@ public
|
|
132
128
|
end
|
133
129
|
end
|
134
130
|
|
135
|
-
|
131
|
+
end # class
|
136
132
|
|
133
|
+
=begin
|
137
134
|
|
138
135
|
# Add a Key-Value for every search parameter you'd usually have.
|
139
136
|
query={"jql"=>"project = MFTP", "startAt"=>0, "maxResults"=>4 }
|
data/lib/credentials.rb
CHANGED
@@ -18,9 +18,7 @@
|
|
18
18
|
|
19
19
|
require "uri"
|
20
20
|
|
21
|
-
|
22
|
-
A Credentials object contains the data required to connect to a JIRA(tm) instance.
|
23
|
-
=end
|
21
|
+
# A Credentials object contains the data required to connect to a JIRA(tm) instance.
|
24
22
|
class Credentials
|
25
23
|
|
26
24
|
# username to use
|
@@ -30,10 +28,10 @@ class Credentials
|
|
30
28
|
# url to connect to the JIRA(tm) instance
|
31
29
|
attr_reader :connecturl
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
|
32
|
+
# @param [String] url URL to JIRA(tm) instance
|
33
|
+
# @param [String] username
|
34
|
+
# @param [String] password
|
37
35
|
def initialize(url,username,password)
|
38
36
|
@username = username
|
39
37
|
@password = password
|
@@ -45,11 +43,8 @@ class Credentials
|
|
45
43
|
end
|
46
44
|
end
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
Throws an Jirarest2::NotAnURLError if the given String is not an URI.
|
52
|
-
=end
|
46
|
+
# Throws an Jirarest2::NotAnURLError if the given String is not an URI.
|
47
|
+
# @param [String] url
|
53
48
|
def connecturl=(url)
|
54
49
|
uri = URI(url)
|
55
50
|
if uri.instance_of?(URI::HTTP) || uri.instance_of?(URI::HTTPS) then
|
data/lib/exceptions.rb
CHANGED
data/lib/issue.rb
CHANGED
@@ -16,11 +16,10 @@
|
|
16
16
|
#
|
17
17
|
|
18
18
|
=begin
|
19
|
-
An Issue object contains all the data of an issue
|
19
|
+
# An Issue object contains all the data of an issue
|
20
20
|
=end
|
21
21
|
class Issue
|
22
|
-
|
23
|
-
|
22
|
+
|
24
23
|
# issue type of the issue
|
25
24
|
attr_reader :issuetype
|
26
25
|
# project the issue belongs to
|
@@ -28,10 +27,9 @@ class Issue
|
|
28
27
|
# The issue numer if we got it somehow
|
29
28
|
attr_reader :issuekey
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
=end
|
30
|
+
# @param [String] project Key of the JIRA(tm) project the issue belongs to
|
31
|
+
# @param [String] type Issuetype the issue belongs to
|
32
|
+
# @param [Connection] connection
|
35
33
|
def initialize (project,type,connection)
|
36
34
|
query = {:projectKeys => project, :issuetypeNames => type, :expand => "projects.issuetypes.fields" }
|
37
35
|
answer = connection.execute("Get","issue/createmeta/",query)
|
@@ -41,10 +39,8 @@ class Issue
|
|
41
39
|
raise Jirarest2::WrongIssuetypeException, type if @issuetype == ""
|
42
40
|
end
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
It produces an instance-variable @issuefields that can be
|
47
|
-
=end
|
42
|
+
# produces an instance-variable @issuefields that can be
|
43
|
+
# @param [Hash] jhash Hashed version of the json-snippet JIRA(tm) returns
|
48
44
|
def parse_json (jhash)
|
49
45
|
@issuefields = Hash.new
|
50
46
|
@project = ""
|
@@ -84,9 +80,8 @@ class Issue
|
|
84
80
|
}
|
85
81
|
end
|
86
82
|
|
87
|
-
|
88
|
-
|
89
|
-
=end
|
83
|
+
# @param [String] field Name of the field
|
84
|
+
# @return [String] type of the Field
|
90
85
|
def fieldtype(field)
|
91
86
|
# If the fieldname is wrong we want to tell this and stop execution (or maybe let the caller fix it)
|
92
87
|
if @issuefields[field].nil? then
|
@@ -96,9 +91,7 @@ class Issue
|
|
96
91
|
end
|
97
92
|
end
|
98
93
|
|
99
|
-
|
100
|
-
Return all the fields that are required for this issuetype
|
101
|
-
=end
|
94
|
+
# @return [Array] Names of required fields
|
102
95
|
def get_requireds
|
103
96
|
names = Array.new
|
104
97
|
@issuefields.each {|key,value|
|
@@ -109,9 +102,7 @@ class Issue
|
|
109
102
|
return names
|
110
103
|
end
|
111
104
|
|
112
|
-
|
113
|
-
Return all the names of the fields
|
114
|
-
=end
|
105
|
+
# @return [Array] Names of all fields
|
115
106
|
def get_fieldnames
|
116
107
|
names = Array.new
|
117
108
|
@issuefields.each {|key,value|
|
@@ -120,26 +111,25 @@ class Issue
|
|
120
111
|
return names
|
121
112
|
end
|
122
113
|
|
123
|
-
|
124
|
-
return
|
125
|
-
=end
|
114
|
+
# @param [String] name Name of a field
|
115
|
+
# @return [String] id of the field
|
126
116
|
protected
|
127
117
|
def get_id(name)
|
128
118
|
return @issuefields["name"]["id"]
|
129
119
|
end
|
130
120
|
|
131
121
|
=begin
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
"
|
138
|
-
|
139
|
-
|
140
|
-
}
|
141
|
-
}
|
122
|
+
# query=
|
123
|
+
# {"fields"=>
|
124
|
+
# { "project"=>{"key"=>"MFTP"},
|
125
|
+
# "environment"=>"REST ye merry gentlemen.",
|
126
|
+
# "My own text"=>"Creating of an issue using project keys and issue type names using the REST API",
|
127
|
+
# "issuetype"=> {"name"=>"My own type"}
|
128
|
+
# }
|
129
|
+
# }
|
142
130
|
=end
|
131
|
+
|
132
|
+
# @return [Hash] Hash to be sent to JIRA(tm) in a JSON representation
|
143
133
|
public
|
144
134
|
def jirahash
|
145
135
|
h = Hash.new
|
@@ -161,9 +151,10 @@ query=
|
|
161
151
|
return h
|
162
152
|
end
|
163
153
|
|
164
|
-
|
165
|
-
|
166
|
-
|
154
|
+
# check if the value is allowed for this field
|
155
|
+
# @param [String] key Name of the field
|
156
|
+
# @param [String] value Value to be checked
|
157
|
+
# @return [Boolean, Jirarest2::ValueNotAllowedException]
|
167
158
|
protected
|
168
159
|
def value_allowed?(key,value)
|
169
160
|
if @issuefields[key]["allowedValues"].include?(value)
|
@@ -174,11 +165,12 @@ query=
|
|
174
165
|
end
|
175
166
|
end
|
176
167
|
|
177
|
-
=begin
|
178
|
-
Special setter for fields that have a limited numer of allowed values.
|
179
168
|
|
180
|
-
|
181
|
-
|
169
|
+
# Special setter for fields that have a limited numer of allowed values.
|
170
|
+
#
|
171
|
+
# This setter might be included in set_field at a later date.
|
172
|
+
# @param [String] key Name of the field
|
173
|
+
# @param [String] value Value to be checked
|
182
174
|
def set_allowed_value(key,value)
|
183
175
|
if @issuefields[key]["type"] == "array" && value.instance_of?(Array) then
|
184
176
|
array = Array.new
|
@@ -195,12 +187,10 @@ query=
|
|
195
187
|
end
|
196
188
|
end
|
197
189
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
TODO We are not yet able to work with "Cascading Select" fields ( "custom": "com.atlassian.jira.plugin.system.customfieldtypes:cascadingselect")
|
203
|
-
=end
|
190
|
+
|
191
|
+
# TODO We are not yet able to work with "Cascading Select" fields ( "custom": "com.atlassian.jira.plugin.system.customfieldtypes:cascadingselect")
|
192
|
+
# @param [String] key Name of the field
|
193
|
+
# @param [String] value Value the field should be set to, this is either a String or an Array (don't know if numbers work too)
|
204
194
|
public
|
205
195
|
def set_field(key, value)
|
206
196
|
if @issuefields.include?(key) then
|
@@ -215,16 +205,15 @@ TODO We are not yet able to work with "Cascading Select" fields ( "custom": "com
|
|
215
205
|
end
|
216
206
|
end
|
217
207
|
|
218
|
-
|
219
|
-
|
220
|
-
=end
|
208
|
+
# @param [String] field Name of the field
|
209
|
+
# @return [String] value of the field
|
221
210
|
def get_field(field)
|
222
211
|
@issuefields[field]["value"]
|
223
212
|
end
|
224
213
|
|
225
|
-
|
226
|
-
|
227
|
-
|
214
|
+
# persitence of this Issue object instance
|
215
|
+
# @param [Connection] connection
|
216
|
+
# @return [Jirarest2::Result]
|
228
217
|
def persist(connection)
|
229
218
|
get_requireds.each { |fieldname|
|
230
219
|
if @issuefields[fieldname]["value"].nil? then
|
@@ -240,10 +229,11 @@ TODO We are not yet able to work with "Cascading Select" fields ( "custom": "com
|
|
240
229
|
end
|
241
230
|
|
242
231
|
|
243
|
-
|
244
|
-
Set the watchers for this Ticket
|
245
|
-
|
246
|
-
|
232
|
+
|
233
|
+
# Set the watchers for this Ticket
|
234
|
+
# @param [Connection] connection
|
235
|
+
# @param [Array] watchers Watchers to be added
|
236
|
+
# @return [Boolean] True if successfull for all
|
247
237
|
def add_watchers(connection,watchers)
|
248
238
|
success = false # Return whether we were successful with the watchers
|
249
239
|
watch = Watcher.new(connection,@issuekey)
|
@@ -255,5 +245,3 @@ TODO We are not yet able to work with "Cascading Select" fields ( "custom": "com
|
|
255
245
|
|
256
246
|
|
257
247
|
end # class
|
258
|
-
|
259
|
-
|
data/lib/jirarest2.rb
CHANGED
data/lib/jirarest2/result.rb
CHANGED
@@ -20,36 +20,40 @@
|
|
20
20
|
require 'json'
|
21
21
|
|
22
22
|
module Jirarest2
|
23
|
-
=begin
|
24
|
-
An object of Result contians the result of a Net::HTTP REST request that has a JSON-Body with easily accessable parameters.
|
25
|
-
=end
|
26
|
-
class Result
|
27
23
|
|
24
|
+
# An object of Result contians the result of a Net::HTTP REST request that has a JSON-Body with easily accessable parameters.
|
25
|
+
class Result
|
26
|
+
|
28
27
|
# The statuscode of the result
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# pp httpResponse
|
42
|
-
# pp httpResponse.
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
28
|
+
attr_reader :code
|
29
|
+
# header lines
|
30
|
+
attr_reader :header
|
31
|
+
# The original body of the result
|
32
|
+
attr_reader :body
|
33
|
+
# The JSON part of the body
|
34
|
+
attr_reader :result
|
35
|
+
|
36
|
+
|
37
|
+
# Show the result in a more usable form
|
38
|
+
# @param [Net::HTTPResponse]
|
39
|
+
def initialize(httpResponse)
|
40
|
+
# pp httpResponse
|
41
|
+
# pp httpResponse.class
|
42
|
+
# pp httpResponse.body
|
43
|
+
@code = httpResponse.code
|
44
|
+
@header = httpResponse.to_hash
|
45
|
+
@body = httpResponse.body
|
46
|
+
#pp @body
|
47
|
+
if httpResponse.instance_of?(Net::HTTPNoContent) or httpResponse.body == "" then # If there is nothing in the body it would be hard to parse it.
|
48
|
+
@result = @body
|
49
|
+
else
|
50
|
+
@result = JSON.parse(@body)
|
51
|
+
end
|
52
|
+
#pp @code
|
53
|
+
#pp @header
|
54
|
+
|
55
|
+
end # initialize
|
56
|
+
|
57
|
+
end # class
|
58
|
+
|
55
59
|
end # module
|
data/lib/madbitconfig.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# Module to handle configuration files
|
2
|
+
# Copyright (C) 2012 Cyril Bitterich
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
#
|
17
|
+
|
18
|
+
# Module to handle configuration files
|
19
|
+
module MadbitConfig
|
20
|
+
|
21
|
+
|
22
|
+
# Special exception to make the point why we threw it around
|
23
|
+
class FileExistsException < IOError ; end
|
24
|
+
|
25
|
+
|
26
|
+
# Inspired by http://www.erickcantwell.com/2011/01/simple-configuration-file-reading-with-ruby/
|
27
|
+
|
28
|
+
# reads a config-file and returns a hash
|
29
|
+
# @param [String] configfile
|
30
|
+
def self.read_configfile(config_file)
|
31
|
+
config_file = File.expand_path(config_file)
|
32
|
+
|
33
|
+
unless File.exists?(config_file) then
|
34
|
+
raise IOError, "Unable to find config file \"#{config_file}\""
|
35
|
+
end
|
36
|
+
|
37
|
+
regexp = Regexp.new(/\s+|"|\[|\]/)
|
38
|
+
|
39
|
+
temp = Array.new
|
40
|
+
vars = Hash.new
|
41
|
+
|
42
|
+
IO.foreach(config_file) { |line|
|
43
|
+
if line.match(/^\s*#/) # don't care about lines starting with an # (even after whitespace)
|
44
|
+
next
|
45
|
+
elsif line.match(/^\s*$/) # no text, no content
|
46
|
+
next
|
47
|
+
else
|
48
|
+
# Right now I don't know what to use scan for. It will escape " nice enough. But once that is excaped the regexp doesn't work any longer.
|
49
|
+
# temp[0],temp[1] = line.to_s.scan(/^.*$/).to_s.split("=")
|
50
|
+
temp[0],temp[1] = line.to_s.split("=")
|
51
|
+
temp.collect! { |val|
|
52
|
+
val.gsub(regexp, "")
|
53
|
+
}
|
54
|
+
vars[temp[0]] = temp[1]
|
55
|
+
end
|
56
|
+
}
|
57
|
+
return vars
|
58
|
+
end # read.configfile
|
59
|
+
|
60
|
+
|
61
|
+
# write a configfile
|
62
|
+
# @param [String] config_file Name (and path) of the config file
|
63
|
+
# @param [Hash] configoptions Hash of "option" => "value" pairs
|
64
|
+
# @param [Symbol] save Determines if an existing file is to be kept. :force replaces an existing file
|
65
|
+
def self.write_configfile(config_file, configoptions, save = :noforce)
|
66
|
+
config_file = File.expand_path(config_file) # Be save
|
67
|
+
|
68
|
+
# First we make sure we don't overwrite a file if the save - flag is set.
|
69
|
+
if save != :force then
|
70
|
+
if File.exists?(config_file) then
|
71
|
+
raise FileExistsException, config_file
|
72
|
+
end
|
73
|
+
end
|
74
|
+
# write the file
|
75
|
+
File.open(config_file, File::CREAT|File::TRUNC|File::RDWR,0600) { |f|
|
76
|
+
configoptions.each { |option,value|
|
77
|
+
f.write( option + " = " + value + "\n")
|
78
|
+
}
|
79
|
+
} # File
|
80
|
+
end # write_configfile
|
81
|
+
|
82
|
+
end # module
|