jirarest2 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +14 -0
- data/README.txt +1 -1
- data/bin/jira_create_issue +79 -21
- data/lib/jirarest2.rb +1 -1
- data/lib/jirarest2/connect.rb +1 -1
- data/lib/jirarest2/exceptions.rb +11 -1
- data/lib/jirarest2/issue.rb +4 -4
- data/lib/jirarest2/result.rb +1 -1
- data/lib/jirarest2/services/issuelink.rb +1 -2
- data/test/test_connect.rb +8 -4
- data/test/test_issue.rb +10 -0
- metadata +3 -3
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
=== 0.0.8 / 2012-07-25
|
2
|
+
|
3
|
+
* 1 minor enhancement:
|
4
|
+
|
5
|
+
* jira_create_issue : Extended the possibilities with the -C paramter. You can now just pass on the content data or use an extended JSON to add project, issue, watchers and links. See --help-C . fixes #9 fixes #10
|
6
|
+
|
7
|
+
* 1 bug fix:
|
8
|
+
|
9
|
+
* Fixed #17 and added a test to catch that behaviour in the future
|
10
|
+
|
11
|
+
* 1 unknown:
|
12
|
+
|
13
|
+
* Fixed bugs with mocked tests.
|
14
|
+
|
1
15
|
=== 0.0.7 / 2012-07-23
|
2
16
|
|
3
17
|
* 2 major enhancements:
|
data/README.txt
CHANGED
@@ -10,7 +10,7 @@ It is intended to be called within the shell to create and verify JIRA(tm) issue
|
|
10
10
|
|
11
11
|
This implementation is still a for cry from others like http://rubygems.org/gems/jira-ruby which required oauth authentification.
|
12
12
|
|
13
|
-
The script allows you to create new issues with watchers and link those to existing issues
|
13
|
+
The script allows you to create new issues with watchers and link those to existing issues.
|
14
14
|
|
15
15
|
*Use it at your own risk. Most of the API features are not implemented.*
|
16
16
|
|
data/bin/jira_create_issue
CHANGED
@@ -33,6 +33,39 @@ require "uri"
|
|
33
33
|
require "pp"
|
34
34
|
|
35
35
|
class ParseOptions
|
36
|
+
|
37
|
+
#print to Variants of a JSON file that we both take in as input with -C
|
38
|
+
def self.print_json_input
|
39
|
+
fullExample = '{
|
40
|
+
"metadata":{
|
41
|
+
"project":"SP",
|
42
|
+
"issue":"Bug",
|
43
|
+
"link":{ "SP-13":"blocks" },
|
44
|
+
"watcher":["test","admin"]
|
45
|
+
},
|
46
|
+
"content":{
|
47
|
+
"Summary":"Your Summary",
|
48
|
+
"Priority":"Trivial"
|
49
|
+
}
|
50
|
+
}'
|
51
|
+
smallExample = '{
|
52
|
+
"Summary" : "Your Summary",
|
53
|
+
"Priority" : "Trivial"
|
54
|
+
}'
|
55
|
+
division = '--------------------------------------------------------'
|
56
|
+
puts division
|
57
|
+
puts "There are two ways you can input data via -C ."
|
58
|
+
puts "Here are two examples to build from. "
|
59
|
+
puts division
|
60
|
+
puts "Using the command line parameters -p, -i, -l and/or -w :"
|
61
|
+
puts smallExample
|
62
|
+
puts division
|
63
|
+
puts "Without the need for any other command line parameters:"
|
64
|
+
puts fullExample
|
65
|
+
puts '"watcher" always needs to be an array. No matter how many entries you got.'
|
66
|
+
puts "You can even mix command line and -C . In this case -C will take precendence."
|
67
|
+
end
|
68
|
+
|
36
69
|
|
37
70
|
def self.required_argument(name)
|
38
71
|
puts "Argument \"#{name}\" is mandatory."
|
@@ -76,7 +109,7 @@ class ParseOptions
|
|
76
109
|
issueopts.content = list
|
77
110
|
end
|
78
111
|
|
79
|
-
opts.on("-C", "--content-file FILENAME", "JSON formatted file (or \"-\" for STDIN)
|
112
|
+
opts.on("-C", "--content-file FILENAME", "JSON formatted file (or \"-\" for STDIN). The file can contain just -c or -c, -i and -p. (Pipes only work if URL,username AND password are in the CONFIGFILE!)") do |contentfile|
|
80
113
|
scriptopts.contentfile = contentfile
|
81
114
|
end
|
82
115
|
|
@@ -85,7 +118,7 @@ class ParseOptions
|
|
85
118
|
end
|
86
119
|
|
87
120
|
opts.on("-l", "--link ISSUEKEY=LINKTYPE", "Key of an Issue this issue should be linked to" ) do |l|
|
88
|
-
|
121
|
+
scriptopts.linkdestkey, scriptopts.linktype = l.split("=")
|
89
122
|
end
|
90
123
|
|
91
124
|
opts.on("-F", "--field-seperator CHAR", "A fieldseperator if one of the fields is an array (Default \"|\")") do |fs|
|
@@ -121,6 +154,10 @@ class ParseOptions
|
|
121
154
|
scriptopts.url = url
|
122
155
|
end
|
123
156
|
|
157
|
+
opts.on_tail("--help-C", "Example input for -C") do
|
158
|
+
print_json_input
|
159
|
+
exit
|
160
|
+
end
|
124
161
|
opts.on_tail("-h", "--help", "Display this screen") do
|
125
162
|
puts opts
|
126
163
|
exit
|
@@ -134,13 +171,6 @@ class ParseOptions
|
|
134
171
|
|
135
172
|
|
136
173
|
opts.parse!(args)
|
137
|
-
|
138
|
-
if issueopts.project.nil? && scriptopts.writeconf.nil? then
|
139
|
-
required_argument("project")
|
140
|
-
end
|
141
|
-
if issueopts.issue.nil? && scriptopts.writeconf.nil? then
|
142
|
-
required_argument("issue")
|
143
|
-
end
|
144
174
|
return issueopts, scriptopts
|
145
175
|
end #parse()
|
146
176
|
|
@@ -184,7 +214,6 @@ def get_credentials
|
|
184
214
|
end
|
185
215
|
@scriptopts.url = @scriptopts.url + "/rest/api/2/"
|
186
216
|
|
187
|
-
|
188
217
|
if @scriptopts.pass.nil? && !( @scriptopts.username.nil?) then
|
189
218
|
@scriptopts.pass = get_password
|
190
219
|
end
|
@@ -224,6 +253,12 @@ end
|
|
224
253
|
=end
|
225
254
|
def open_issue
|
226
255
|
begin
|
256
|
+
if @issueopts.project.nil? then
|
257
|
+
ParseOptions::required_argument("project")
|
258
|
+
end
|
259
|
+
if @issueopts.issue.nil? then
|
260
|
+
ParseOptions::required_argument("issue")
|
261
|
+
end
|
227
262
|
credentials = get_credentials
|
228
263
|
issue=Issue.new(@issueopts.project,@issueopts.issue,get_connection)
|
229
264
|
rescue Jirarest2::AuthentificationError => e
|
@@ -272,16 +307,37 @@ def split_content(issue)
|
|
272
307
|
return fields
|
273
308
|
end
|
274
309
|
|
310
|
+
# interpret input from file or STDIN
|
311
|
+
def get_jsondata_from_file
|
312
|
+
data = MadbitConfig::read_configfile(@scriptopts.contentfile)
|
313
|
+
content = Hash.new
|
314
|
+
if data["metadata"] then # We have metadata and content
|
315
|
+
content = data["content"]
|
316
|
+
pp "metadata"
|
317
|
+
@issueopts.project = data["metadata"]["project"] if data["metadata"]["project"]
|
318
|
+
@issueopts.issue = data["metadata"]["issue"] if data["metadata"]["issue"]
|
319
|
+
pp data["metadata"]["watcher"].class
|
320
|
+
pp data["metadata"]["watcher"]
|
321
|
+
@issueopts.watchers = data["metadata"]["watcher"] if data["metadata"]["watcher"]
|
322
|
+
pp data["metadata"]["link"]
|
323
|
+
@scriptopts.linkdestkey, @scriptopts.linktype = data["metadata"]["link"].flatten if data["metadata"]["link"]
|
324
|
+
else # We have the simple format that carries only the content
|
325
|
+
content = data
|
326
|
+
end
|
327
|
+
return content
|
328
|
+
end
|
329
|
+
|
275
330
|
# Prepare a new ticket. It will not be persisted yet.
|
276
331
|
def prepare_new_ticket
|
277
332
|
begin
|
278
|
-
issue = open_issue
|
279
333
|
if @scriptopts.contentfile then
|
280
334
|
#Input from file or STDIN
|
281
335
|
puts "Your Input now"
|
282
|
-
fields =
|
336
|
+
fields = get_jsondata_from_file
|
337
|
+
issue = open_issue
|
283
338
|
else
|
284
339
|
#Input from the command line
|
340
|
+
issue = open_issue
|
285
341
|
fields = split_content(issue)
|
286
342
|
end
|
287
343
|
valueNotAllowedRaised = false
|
@@ -293,15 +349,14 @@ def prepare_new_ticket
|
|
293
349
|
rescue Jirarest2::WrongFieldnameException => e
|
294
350
|
no_issue("field",e)
|
295
351
|
rescue Jirarest2::ValueNotAllowedException => e
|
296
|
-
puts "Value #{
|
297
|
-
puts "Please use one of: \"" + e.
|
352
|
+
puts "Value #{e} not allowed for field #{e.fieldname}."
|
353
|
+
puts "Please use one of: \"" + e.allowed.join("\", \"") + "\""
|
298
354
|
valueNotAllowedRaised = true
|
299
355
|
end
|
300
|
-
|
301
|
-
}
|
302
|
-
=end
|
356
|
+
|
303
357
|
if valueNotAllowedRaised then
|
304
|
-
|
358
|
+
puts "Exiting before trying to create an issue."
|
359
|
+
exit 1
|
305
360
|
end
|
306
361
|
return issue
|
307
362
|
end
|
@@ -334,16 +389,19 @@ def create_new_ticket(issue)
|
|
334
389
|
puts "Watchers could not be set though."
|
335
390
|
end
|
336
391
|
begin
|
337
|
-
if @
|
392
|
+
if @scriptopts.linkdestkey then
|
338
393
|
link = IssueLink.new(connection)
|
339
|
-
|
340
|
-
linkresult = link.link(result["key"],remoteIssue,linktype)
|
394
|
+
linkresult = link.link(result["key"],@scriptopts.linkdestkey,@scriptopts.linktype)
|
341
395
|
end
|
342
396
|
rescue Jirarest2::ValueNotAllowedException => e
|
343
397
|
puts "Link not created. Issuetype \"#{e.message}\" not valid."
|
344
398
|
puts "Please use one of the these:"
|
345
399
|
puts link.valid_issuelinktypes("\n")
|
346
400
|
exit 1
|
401
|
+
rescue Jirarest2::NotFoundError => e
|
402
|
+
puts "Link not created. One of the issues not found. Jira says:"
|
403
|
+
puts e.to_s
|
404
|
+
exit 1
|
347
405
|
end
|
348
406
|
return 0
|
349
407
|
elsif result["errors"] then
|
data/lib/jirarest2.rb
CHANGED
data/lib/jirarest2/connect.rb
CHANGED
@@ -77,7 +77,7 @@ class Connect
|
|
77
77
|
result.get_fields("x-authentication-denied-reason")[0] =~ /.*login-url=(.*)/
|
78
78
|
raise Jirarest2::AuthentificationCaptchaError, $1
|
79
79
|
when Net::HTTPNotFound
|
80
|
-
raise Jirarest2::NotFoundError, result
|
80
|
+
raise Jirarest2::NotFoundError, result.body
|
81
81
|
end
|
82
82
|
|
83
83
|
return Jirarest2::Result.new(result)
|
data/lib/jirarest2/exceptions.rb
CHANGED
@@ -43,7 +43,17 @@ module Jirarest2
|
|
43
43
|
# There is no field with this name for the given issue type
|
44
44
|
class WrongFieldnameException < ArgumentError; end
|
45
45
|
# value is not allowed for this type of fields
|
46
|
-
class ValueNotAllowedException < ArgumentError
|
46
|
+
class ValueNotAllowedException < ArgumentError
|
47
|
+
# The name of the field the value does not match to
|
48
|
+
attr_reader :fieldname
|
49
|
+
# Matching values
|
50
|
+
attr_reader :allowed
|
51
|
+
|
52
|
+
def initialize(fieldname,allowed)
|
53
|
+
@fieldname = fieldname
|
54
|
+
@allowed = allowed
|
55
|
+
end
|
56
|
+
end
|
47
57
|
# A field that is defined as "required" has not been given a value
|
48
58
|
class RequiredFieldNotSetException < ArgumentError; end
|
49
59
|
|
data/lib/jirarest2/issue.rb
CHANGED
@@ -49,7 +49,7 @@ class Issue
|
|
49
49
|
@project = value["key"]
|
50
50
|
value["issuetypes"].each { |value1|
|
51
51
|
@issuetype = value1["name"]
|
52
|
-
value1["fields"].delete("project") #The project key is duplicate and will make
|
52
|
+
value1["fields"].delete("project") #The project key is duplicate and will make our live harder afterwards. It is marked as required but nothing happens if this key is not set.
|
53
53
|
value1["fields"].each { |key,value2|
|
54
54
|
fields = Hash.new
|
55
55
|
fields["id"] = key
|
@@ -59,7 +59,7 @@ class Issue
|
|
59
59
|
name = key
|
60
60
|
end
|
61
61
|
# If the allowed reponses are limited we want to know them.
|
62
|
-
if
|
62
|
+
if value2["allowedValues"] then
|
63
63
|
# With custom fields the identifier is "value" with the built in ones it's "name"
|
64
64
|
identifier = "name"
|
65
65
|
if value2["schema"]["custom"] then
|
@@ -160,8 +160,8 @@ class Issue
|
|
160
160
|
if @issuefields[key]["allowedValues"].include?(value)
|
161
161
|
return true
|
162
162
|
else
|
163
|
-
|
164
|
-
|
163
|
+
# puts "Value #{value} not allowed for field #{key}."
|
164
|
+
raise Jirarest2::ValueNotAllowedException.new(key, @issuefields[key]["allowedValues"]), value
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
data/lib/jirarest2/result.rb
CHANGED
@@ -44,7 +44,7 @@ module Jirarest2
|
|
44
44
|
@header = httpResponse.to_hash
|
45
45
|
@body = httpResponse.body
|
46
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.
|
47
|
+
if httpResponse.instance_of?(Net::HTTPNoContent) or httpResponse.body == "" or httpResponse.body.nil? then # If there is nothing in the body it would be hard to parse it.
|
48
48
|
@result = @body
|
49
49
|
else
|
50
50
|
@result = JSON.parse(@body)
|
@@ -67,7 +67,7 @@ class IssueLink < Services
|
|
67
67
|
if ! @linktype.internal_name?(type) then # time to find the correct name and see if we have to exchange tickets
|
68
68
|
realname = @linktype.name(type)
|
69
69
|
if realname.nil? then
|
70
|
-
raise Jirarest2::ValueNotAllowedException, type
|
70
|
+
raise Jirarest2::ValueNotAllowedException.new(type,valid_issuelinktypes), type
|
71
71
|
else
|
72
72
|
type = realname[0]
|
73
73
|
if realname[1] == "inward" then # we have to change the issues as jira only knows one direction.
|
@@ -85,7 +85,6 @@ class IssueLink < Services
|
|
85
85
|
json["inwardIssue"] = { "key" => inwardIssue }
|
86
86
|
json["outwardIssue"] = { "key" => outwardIssue }
|
87
87
|
json["comment"] = { "body" => comment} if comment
|
88
|
-
|
89
88
|
return post(json)
|
90
89
|
end
|
91
90
|
|
data/test/test_connect.rb
CHANGED
@@ -14,15 +14,19 @@ class TestConnect < MiniTest::Unit::TestCase
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def test_executeGET
|
17
|
-
stub_request(:get, "http://test:1234@localhost:2990/jira/rest/api/2/issue/createmeta/").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 200, :body => "", :headers => {})
|
18
|
-
|
17
|
+
stub_request(:get, "http://test:1234@localhost:2990/jira/rest/api/2/issue/createmeta/").with(:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 200, :body => '{"expand":"projects"}', :headers => {})
|
18
|
+
assert_equal "projects", @con.execute("Get","issue/createmeta/","").result["expand"]
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_executePOST
|
22
|
-
stub_request(:post, "http://test:1234@localhost:2990/jira/rest/api/2/search/").with(:body => "{\"jql\":\"project = MFTP\",\"startAt\":0,\"maxResults\":4}",:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 200, :body => "", :headers => {})
|
22
|
+
stub_request(:post, "http://test:1234@localhost:2990/jira/rest/api/2/search/").with(:body => "{\"jql\":\"project = MFTP\",\"startAt\":0,\"maxResults\":4}",:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 200, :body => '{"expand":"schema,names","startAt":0,"maxResults":4,"total":9,"issues":[{"expand":"editmeta,renderedFields,transitions,changelog,operations","id":"10102","self":"http://localhost:2990/jira/rest/api/2/issue/10102","key":"MFTP-9","fields":{"summary":"AnotherissueatSunJul1516","progress":{"progress":0,"total":0}}}]}', :headers => {})
|
23
|
+
# WebMock.disable!
|
23
24
|
|
24
25
|
query={"jql"=>"project = MFTP", "startAt"=>0, "maxResults"=>4 }
|
25
|
-
|
26
|
+
assert_equal 4, @con.execute("Post","search/",query).result["maxResults"]
|
27
|
+
# WebMock.enable!
|
28
|
+
|
29
|
+
pp @con.execute("Post","search/",query).result["maxResults"]
|
26
30
|
end
|
27
31
|
|
28
32
|
def test_check_uri_true
|
data/test/test_issue.rb
CHANGED
@@ -54,5 +54,15 @@ class TestIssue < MiniTest::Unit::TestCase
|
|
54
54
|
assert_equal "Summary Text", issue.get_field("Summary")
|
55
55
|
end
|
56
56
|
|
57
|
+
|
58
|
+
def test_persist
|
59
|
+
issue = @existentIssue
|
60
|
+
issue.set_field("Summary","Summary Text")
|
61
|
+
issue.set_field("Priority","Trivial")
|
62
|
+
stub_request(:post, "http://test:1234@localhost:2990/jira/rest/api/2/issue/").with(:body => "{\"fields\":{\"project\":{\"key\":\"MFTP\"},\"summary\":\"Summary Text\",\"priority\":{\"name\":\"Trivial\"},\"issuetype\":{\"name\":\"My issue type\"}}}",:headers => {'Accept'=>'*/*', 'Content-Type'=>'application/json;charset=UTF-8', 'User-Agent'=>'Ruby'}).to_return(:status => 201, :body => '{"id":"10608","key":"MFTP-11","self":"http://localhost:2990/jira/rest/api/2/issue/10608"}', :headers => {})
|
63
|
+
|
64
|
+
issue.persist(@connect)
|
65
|
+
end
|
66
|
+
|
57
67
|
|
58
68
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jirarest2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -50,7 +50,7 @@ cert_chain:
|
|
50
50
|
-----END CERTIFICATE-----
|
51
51
|
|
52
52
|
'
|
53
|
-
date: 2012-07-
|
53
|
+
date: 2012-07-24 00:00:00.000000000 Z
|
54
54
|
dependencies:
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: json
|
@@ -138,7 +138,7 @@ description: ! "jirarest2 is yet another implementation of the JIRA(tm) REST-API
|
|
138
138
|
for perfomance at the time of writing.\n\nThis implementation is still a for cry
|
139
139
|
from others like http://rubygems.org/gems/jira-ruby which required oauth authentification.
|
140
140
|
\n\nThe script allows you to create new issues with watchers and link those to existing
|
141
|
-
issues
|
141
|
+
issues.\n\n *Use it at your own risk. Most of the API features are not implemented.*\n\n
|
142
142
|
*Ruby1.9.1 is needed. Ruby1.8 doesn't work!*"
|
143
143
|
email:
|
144
144
|
- cebit-jirarest@gunnet.de
|
metadata.gz.sig
CHANGED
Binary file
|