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 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
 
@@ -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) with the contents of -c which will be ignored (Pipes work only if URL,username AND password are in the CONFIGFILE!)") do |contentfile|
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
- issueopts.link = l
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 = MadbitConfig::read_configfile(@scriptopts.contentfile)
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 #{split[1]} not allowed for field #{split[0]}."
297
- puts "Please use one of: \"" + e.message.join("\", \"") + "\""
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
- =begin
301
- }
302
- =end
356
+
303
357
  if valueNotAllowedRaised then
304
- raise Jirarest2::ValueNotAllowedException
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 @issueopts.link then
392
+ if @scriptopts.linkdestkey then
338
393
  link = IssueLink.new(connection)
339
- remoteIssue,linktype = @issueopts.link.split("=")
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
@@ -17,7 +17,7 @@
17
17
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
18
  #
19
19
 
20
- VERSION = "0.0.7"
20
+ VERSION = "0.0.8"
21
21
 
22
22
  require_relative "jirarest2/connect"
23
23
  require_relative "jirarest2/issue"
@@ -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)
@@ -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; end
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
 
@@ -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 us live harder afterwards. It is marked as required but nothing happens if this key is not set.
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 value["allowedValues"] then
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
- raise Jirarest2::ValueNotAllowedException, @issuefields[key]["allowedValues"]
164
- puts "Value #{value} not allowed for field #{key}."
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
 
@@ -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
- assert "projects", @con.execute("Get","issue/createmeta/","").result["expand"]
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
- assert 4, @con.execute("Post","search/",query).result["maxResults"]
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.7
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-23 00:00:00.000000000 Z
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\n\n *Use it at your own risk. Most of the API features are not implemented.*\n\n
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