jirarest2 0.0.6 → 0.0.7
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 +17 -0
- data/Manifest.txt +11 -9
- data/README.txt +1 -1
- data/Rakefile +1 -1
- data/bin/create_issue.rb +2 -2
- data/bin/jira_create_issue +397 -0
- data/bin/jira_create_issue.rb +3 -370
- data/lib/jirarest2.rb +8 -8
- data/lib/{connect.rb → jirarest2/connect.rb} +1 -1
- data/lib/{credentials.rb → jirarest2/credentials.rb} +0 -0
- data/lib/{exceptions.rb → jirarest2/exceptions.rb} +0 -0
- data/lib/{issue.rb → jirarest2/issue.rb} +15 -15
- data/lib/{madbitconfig.rb → jirarest2/madbitconfig.rb} +0 -0
- data/lib/{services.rb → jirarest2/services.rb} +0 -0
- data/lib/{services → jirarest2/services}/issuelink.rb +14 -8
- data/lib/jirarest2/services/issuelinktype.rb +108 -0
- data/lib/{services → jirarest2/services}/watcher.rb +2 -2
- data/test/data/issuespec.txt +14 -0
- data/test/test_connect.rb +28 -5
- data/test/test_issue.rb +7 -1
- data/test/test_issuelink.rb +36 -11
- data/test/test_issuelinktype.rb +30 -5
- data/test/test_madbitconfig.rb +9 -9
- data/test/test_result.rb +19 -5
- data/test/test_watcher.rb +21 -7
- metadata +30 -11
- metadata.gz.sig +0 -0
- data/lib/services/issuelinktype.rb +0 -91
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
=== 0.0.7 / 2012-07-23
|
2
|
+
|
3
|
+
* 2 major enhancements:
|
4
|
+
|
5
|
+
* Moved the library files all one directory down under lib/jirarest2/ and edited the requires fields accodringly. - closes #6
|
6
|
+
* jira_create_issue.rb moved yet again. Now to jira_create_issue - closes #8
|
7
|
+
|
8
|
+
* 1 minor enhancement:
|
9
|
+
|
10
|
+
* rewrote issuelinktype
|
11
|
+
|
12
|
+
* 3 bug fixes:
|
13
|
+
|
14
|
+
* Changed tests to WebMock. No more dependency to existing server fixes #16
|
15
|
+
* Changed the output to something more clear if the linktype is not correct. fixes #11
|
16
|
+
* It is now suficient to enter only -C - fixes #5
|
17
|
+
|
1
18
|
=== 0.0.6 / 2012-07-18
|
2
19
|
|
3
20
|
* 1 minor enhancement:
|
data/Manifest.txt
CHANGED
@@ -5,19 +5,21 @@ Manifest.txt
|
|
5
5
|
README.txt
|
6
6
|
Rakefile
|
7
7
|
bin/create_issue.rb
|
8
|
+
bin/jira_create_issue
|
8
9
|
bin/jira_create_issue.rb
|
9
10
|
copyright
|
10
|
-
lib/connect.rb
|
11
|
-
lib/credentials.rb
|
12
|
-
lib/exceptions.rb
|
13
|
-
lib/issue.rb
|
14
11
|
lib/jirarest2.rb
|
12
|
+
lib/jirarest2/connect.rb
|
13
|
+
lib/jirarest2/credentials.rb
|
14
|
+
lib/jirarest2/exceptions.rb
|
15
|
+
lib/jirarest2/issue.rb
|
16
|
+
lib/jirarest2/madbitconfig.rb
|
15
17
|
lib/jirarest2/result.rb
|
16
|
-
lib/
|
17
|
-
lib/services.rb
|
18
|
-
lib/services/
|
19
|
-
lib/services/
|
20
|
-
|
18
|
+
lib/jirarest2/services.rb
|
19
|
+
lib/jirarest2/services/issuelink.rb
|
20
|
+
lib/jirarest2/services/issuelinktype.rb
|
21
|
+
lib/jirarest2/services/watcher.rb
|
22
|
+
test/data/issuespec.txt
|
21
23
|
test/data/test.config.data
|
22
24
|
test/data/test.json
|
23
25
|
test/data/test.nojson
|
data/README.txt
CHANGED
@@ -19,7 +19,7 @@ The script allows you to create new issues with watchers and link those to exist
|
|
19
19
|
|
20
20
|
== FEATURES/PROBLEMS:
|
21
21
|
|
22
|
-
* Still in the
|
22
|
+
* Still in the alpha stages. The classes are still pretty volatile.
|
23
23
|
* The script allows you to create new issues with watchers and link those to existing issues
|
24
24
|
|
25
25
|
== SYNOPSIS:
|
data/Rakefile
CHANGED
data/bin/create_issue.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
|
-
puts "File has been renamed to jira_create_issue
|
21
|
-
newfile = File.dirname($0) + "/jira_create_issue
|
20
|
+
puts "File has been renamed to jira_create_issue"
|
21
|
+
newfile = File.dirname($0) + "/jira_create_issue"
|
22
22
|
puts "Please use: #{newfile} #{$*.join(" ")}"
|
23
23
|
|
@@ -0,0 +1,397 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Script to create a new issue with jira.
|
4
|
+
# Copyright (C) 2012 Cyril Bitterich
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
#
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
if RUBY_VERSION < "1.9"
|
23
|
+
puts "Sorry, I need ruby 1.9.1 or higher!"
|
24
|
+
exit1
|
25
|
+
end
|
26
|
+
|
27
|
+
require "highline/import"
|
28
|
+
require "jirarest2"
|
29
|
+
require "optparse"
|
30
|
+
require "ostruct"
|
31
|
+
require "jirarest2/madbitconfig"
|
32
|
+
require "uri"
|
33
|
+
require "pp"
|
34
|
+
|
35
|
+
class ParseOptions
|
36
|
+
|
37
|
+
def self.required_argument(name)
|
38
|
+
puts "Argument \"#{name}\" is mandatory."
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
|
42
|
+
=begin
|
43
|
+
parse resturn two Hashes. The first one contains the options for the issue the second one the options for the execution of the script.
|
44
|
+
=end
|
45
|
+
def self.parse(args)
|
46
|
+
issueopts = OpenStruct.new
|
47
|
+
issueopts.project = nil
|
48
|
+
issueopts.issue = nil
|
49
|
+
scriptopts = OpenStruct.new
|
50
|
+
scriptopts.show = []
|
51
|
+
scriptopts.arrayseperator = "|"
|
52
|
+
scriptopts.configfile = "~/.jiraconfig"
|
53
|
+
|
54
|
+
opts = OptionParser.new do |opts|
|
55
|
+
opts.banner = "Usage: #{__FILE__} [options]"
|
56
|
+
opts.separator ""
|
57
|
+
|
58
|
+
opts.on("-p", "--project PROJECT", "Projectname") do |p|
|
59
|
+
issueopts.project = p
|
60
|
+
issueopts
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-i", "--issue ISSUETYPE", "Issuetype") do |i|
|
64
|
+
issueopts.issue = i
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on("-f", "--fields", "Display the fields available for this issue") do |f|
|
68
|
+
scriptopts.show << "fields"
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.on("-r", "--requireds", "Display the the mandatory content fields for this issue") do |r|
|
72
|
+
scriptopts.show << "requireds"
|
73
|
+
end
|
74
|
+
|
75
|
+
opts.on("-c", "--content x=value,y=value,z=value", Array, "List of fields to fill") do |list|
|
76
|
+
issueopts.content = list
|
77
|
+
end
|
78
|
+
|
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|
|
80
|
+
scriptopts.contentfile = contentfile
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on("-w", "--watcher USERNAME,USERNAME", Array, "List of watchers") do |w|
|
84
|
+
issueopts.watchers = w
|
85
|
+
end
|
86
|
+
|
87
|
+
opts.on("-l", "--link ISSUEKEY=LINKTYPE", "Key of an Issue this issue should be linked to" ) do |l|
|
88
|
+
issueopts.link = l
|
89
|
+
end
|
90
|
+
|
91
|
+
opts.on("-F", "--field-seperator CHAR", "A fieldseperator if one of the fields is an array (Default \"|\")") do |fs|
|
92
|
+
scriptopts.arrayseperator = fs
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
opts.on("--config-file CONFIGFILE", "Config file containing the jira credentials. (Default: ~/.jiraconfig)") do |conffile|
|
97
|
+
scriptopts.configfile = conffile
|
98
|
+
end
|
99
|
+
|
100
|
+
opts.on("--write-config-file", "Writes the configfile with the data given if it does not alredy exist.") do |wc|
|
101
|
+
scriptopts.writeconf = :write
|
102
|
+
end
|
103
|
+
|
104
|
+
opts.on("--force-write-config-file", "Writes the configfile with the data given even if it does alredy exist.") do |wc|
|
105
|
+
scriptopts.writeconf = :forcewrite
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
opts.on("-u", "--username USERNAME", "Your Jira Username if you don't want to use the one in the master file") do |u|
|
110
|
+
scriptopts.username = u
|
111
|
+
end
|
112
|
+
|
113
|
+
opts.on("-H", "--jira-url URL", "URL to rest api (without \"/rest/api/2\").") do |url|
|
114
|
+
uri = URI(url)
|
115
|
+
splitURI = URI.split(url)
|
116
|
+
if splitURI[3] then
|
117
|
+
url = splitURI[0].to_s + "://" + splitURI[2].to_s + ":" + splitURI[3].to_s + splitURI[5].to_s
|
118
|
+
else
|
119
|
+
url = splitURI[0].to_s + "://" + splitURI[2].to_s + splitURI[5].to_s
|
120
|
+
end
|
121
|
+
scriptopts.url = url
|
122
|
+
end
|
123
|
+
|
124
|
+
opts.on_tail("-h", "--help", "Display this screen") do
|
125
|
+
puts opts
|
126
|
+
exit
|
127
|
+
end
|
128
|
+
|
129
|
+
opts.on_tail("--version", "Show version") do
|
130
|
+
puts OptionParser::Version.join(".")
|
131
|
+
exit
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
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
|
+
return issueopts, scriptopts
|
145
|
+
end #parse()
|
146
|
+
|
147
|
+
|
148
|
+
end # class ParseOptions
|
149
|
+
|
150
|
+
@issueopts, @scriptopts = ParseOptions.parse(ARGV)
|
151
|
+
|
152
|
+
|
153
|
+
def no_issue(type,issue)
|
154
|
+
puts "The #{type}type you entered (\"#{issue}\") does no exist."
|
155
|
+
puts "Maybe you entered the wrong type or made a typo? (Case is relevant!)"
|
156
|
+
exit 1
|
157
|
+
end
|
158
|
+
|
159
|
+
=begin
|
160
|
+
Get the password from an interactive shell
|
161
|
+
=end
|
162
|
+
def get_password
|
163
|
+
ask("Enter your password for user \"#{@scriptopts.username}\": ") { |q|
|
164
|
+
q.echo = "*"
|
165
|
+
}
|
166
|
+
end
|
167
|
+
|
168
|
+
=begin
|
169
|
+
Gather all the credentials and build the credentials file
|
170
|
+
=end
|
171
|
+
def get_credentials
|
172
|
+
filefail = false
|
173
|
+
begin
|
174
|
+
fileconf = MadbitConfig::read_configfile(@scriptopts.configfile)
|
175
|
+
# We don't want to set the Values from the configfile if we have them already set.
|
176
|
+
@scriptopts.username = fileconf["username"] if ( @scriptopts.username.nil? && fileconf["username"] )
|
177
|
+
@scriptopts.pass = fileconf["password"] if ( @scriptopts.pass.nil? && fileconf["password"] )
|
178
|
+
if ( @scriptopts.url.nil? && fileconf["URL"] ) then
|
179
|
+
@scriptopts.url = fileconf["URL"]
|
180
|
+
end
|
181
|
+
rescue IOError => e
|
182
|
+
puts e
|
183
|
+
filefail = false
|
184
|
+
end
|
185
|
+
@scriptopts.url = @scriptopts.url + "/rest/api/2/"
|
186
|
+
|
187
|
+
|
188
|
+
if @scriptopts.pass.nil? && !( @scriptopts.username.nil?) then
|
189
|
+
@scriptopts.pass = get_password
|
190
|
+
end
|
191
|
+
|
192
|
+
missing = Array.new
|
193
|
+
missing << "URL" if @scriptopts.url.nil?
|
194
|
+
missing << "username" if @scriptopts.username.nil?
|
195
|
+
# missing << "password" if @scriptopts.pass.nil?
|
196
|
+
if missing != [] then
|
197
|
+
puts "Missing essential parameter(s) #{missing.join(",")}. Exiting..."
|
198
|
+
exit 1
|
199
|
+
else
|
200
|
+
return Credentials.new(@scriptopts.url, @scriptopts.username, @scriptopts.pass)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
=begin
|
205
|
+
If there is already a conenction known returns that connection. If not or if the parameter is true it tries to create a new Connect object
|
206
|
+
=end
|
207
|
+
def get_connection(reconnect = false)
|
208
|
+
if ! @connection || reconnect then
|
209
|
+
begin
|
210
|
+
@connection = Connect.new(get_credentials)
|
211
|
+
@connection.heal_uri! # We want to be sure so we try to heal the connection_url if possible
|
212
|
+
return @connection
|
213
|
+
rescue Jirarest2::CouldNotHealURIError => e
|
214
|
+
puts "REST API not found at #{e.to_s}"
|
215
|
+
exit 3
|
216
|
+
end
|
217
|
+
else
|
218
|
+
return @connection
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
=begin
|
223
|
+
create the issue on our side
|
224
|
+
=end
|
225
|
+
def open_issue
|
226
|
+
begin
|
227
|
+
credentials = get_credentials
|
228
|
+
issue=Issue.new(@issueopts.project,@issueopts.issue,get_connection)
|
229
|
+
rescue Jirarest2::AuthentificationError => e
|
230
|
+
puts "Password not accepted."
|
231
|
+
@scriptopts.pass = get_password
|
232
|
+
retry
|
233
|
+
rescue Jirarest2::AuthentificationCaptchaError => e
|
234
|
+
puts "Wrong Password too many times.\nCaptcha time at #{e.to_s} to reenable your account."
|
235
|
+
exit 1
|
236
|
+
rescue Jirarest2::WrongProjectException => e
|
237
|
+
no_issue("project",e)
|
238
|
+
rescue Jirarest2::WrongIssuetypeException => e
|
239
|
+
no_issue("project",e)
|
240
|
+
end
|
241
|
+
return issue
|
242
|
+
end
|
243
|
+
|
244
|
+
=begin
|
245
|
+
Show available fields and required fields
|
246
|
+
=end
|
247
|
+
def show_scheme
|
248
|
+
issue = open_issue
|
249
|
+
if @scriptopts.show.include?("fields") then
|
250
|
+
print "Available fields: "
|
251
|
+
puts issue.get_fieldnames.join(", ")
|
252
|
+
end
|
253
|
+
if @scriptopts.show.include?("requireds") then
|
254
|
+
print "Required fields: "
|
255
|
+
puts issue.get_requireds.join(", ")
|
256
|
+
end
|
257
|
+
exit
|
258
|
+
end
|
259
|
+
|
260
|
+
# Split the content from the command line parameter "-c"
|
261
|
+
def split_content(issue)
|
262
|
+
fields = Hash.new
|
263
|
+
@issueopts.content.each { |value|
|
264
|
+
split = value.split("=")
|
265
|
+
if issue.fieldtype(split[0]) == "array" then # If the fieldtype is an array we want to use our arrayseparator to split the fields
|
266
|
+
if ! split[1].nil? then
|
267
|
+
split[1] = split[1].split(@scriptopts.arrayseperator)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
fields[split[0]] = split[1]
|
271
|
+
}
|
272
|
+
return fields
|
273
|
+
end
|
274
|
+
|
275
|
+
# Prepare a new ticket. It will not be persisted yet.
|
276
|
+
def prepare_new_ticket
|
277
|
+
begin
|
278
|
+
issue = open_issue
|
279
|
+
if @scriptopts.contentfile then
|
280
|
+
#Input from file or STDIN
|
281
|
+
puts "Your Input now"
|
282
|
+
fields = MadbitConfig::read_configfile(@scriptopts.contentfile)
|
283
|
+
else
|
284
|
+
#Input from the command line
|
285
|
+
fields = split_content(issue)
|
286
|
+
end
|
287
|
+
valueNotAllowedRaised = false
|
288
|
+
fields.each { |name,value|
|
289
|
+
issue.set_field(name,value)
|
290
|
+
}
|
291
|
+
rescue JSON::ParserError => e
|
292
|
+
raise JSON::ParserError, e # Maybe I want to make this nice sometimes
|
293
|
+
rescue Jirarest2::WrongFieldnameException => e
|
294
|
+
no_issue("field",e)
|
295
|
+
rescue Jirarest2::ValueNotAllowedException => e
|
296
|
+
puts "Value #{split[1]} not allowed for field #{split[0]}."
|
297
|
+
puts "Please use one of: \"" + e.message.join("\", \"") + "\""
|
298
|
+
valueNotAllowedRaised = true
|
299
|
+
end
|
300
|
+
=begin
|
301
|
+
}
|
302
|
+
=end
|
303
|
+
if valueNotAllowedRaised then
|
304
|
+
raise Jirarest2::ValueNotAllowedException
|
305
|
+
end
|
306
|
+
return issue
|
307
|
+
end
|
308
|
+
|
309
|
+
=begin
|
310
|
+
a little bit to fine - could be put into the method below
|
311
|
+
=end
|
312
|
+
def set_watchers(issue)
|
313
|
+
issue.set_watcher(credentials,@issueopts.watchers)
|
314
|
+
end
|
315
|
+
|
316
|
+
=begin
|
317
|
+
do all the work to actually create a new ticket (persist, watchers, links)
|
318
|
+
=end
|
319
|
+
def create_new_ticket(issue)
|
320
|
+
begin
|
321
|
+
connection = get_connection # We need it so often in the next few lines that I prefer to get the result in a variable
|
322
|
+
result = issue.persist(connection).result
|
323
|
+
# Set the watchers
|
324
|
+
if @issueopts.watchers then
|
325
|
+
watcherssuccess = issue.add_watchers(connection,@issueopts.watchers)
|
326
|
+
end
|
327
|
+
rescue Jirarest2::RequiredFieldNotSetException => e
|
328
|
+
puts "Required field \"#{e.to_s}\" not set."
|
329
|
+
return 1
|
330
|
+
end
|
331
|
+
if result["key"] then
|
332
|
+
puts "Created new issue with issue id #{result["key"]} ."
|
333
|
+
if ! watcherssuccess && @issueopts.watchers then
|
334
|
+
puts "Watchers could not be set though."
|
335
|
+
end
|
336
|
+
begin
|
337
|
+
if @issueopts.link then
|
338
|
+
link = IssueLink.new(connection)
|
339
|
+
remoteIssue,linktype = @issueopts.link.split("=")
|
340
|
+
linkresult = link.link(result["key"],remoteIssue,linktype)
|
341
|
+
end
|
342
|
+
rescue Jirarest2::ValueNotAllowedException => e
|
343
|
+
puts "Link not created. Issuetype \"#{e.message}\" not valid."
|
344
|
+
puts "Please use one of the these:"
|
345
|
+
puts link.valid_issuelinktypes("\n")
|
346
|
+
exit 1
|
347
|
+
end
|
348
|
+
return 0
|
349
|
+
elsif result["errors"] then
|
350
|
+
puts "An error occured. The error message was: #{result["errors"].to_s}"
|
351
|
+
return 2
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
=begin
|
356
|
+
called to write the config file
|
357
|
+
=end
|
358
|
+
def write_configfile
|
359
|
+
text = Hash.new
|
360
|
+
if @scriptopts.url.nil? then
|
361
|
+
text["#URL"] = "https://host.domain.com:port/path/"
|
362
|
+
else
|
363
|
+
text["URL"] = "#{@scriptopts.url}"
|
364
|
+
end
|
365
|
+
if @scriptopts.username.nil? then
|
366
|
+
text["#username"] = "USERNAME"
|
367
|
+
else
|
368
|
+
text["username"] = "#{@scriptopts.username}"
|
369
|
+
end
|
370
|
+
text["#password"] = "Your!PassW0rd"
|
371
|
+
begin
|
372
|
+
if @scriptopts.writeconf == :forcewrite then
|
373
|
+
MadbitConfig::write_configfile(@scriptopts.configfile,text,:force)
|
374
|
+
else
|
375
|
+
MadbitConfig::write_configfile(@scriptopts.configfile,text)
|
376
|
+
end
|
377
|
+
puts "Configfile written to #{@scriptopts.configfile}. Exiting."
|
378
|
+
exit 0
|
379
|
+
rescue MadbitConfig::FileExistsException => e
|
380
|
+
puts "Configfile #{e} already exists. Use \"--force-write-config-file\" to replace."
|
381
|
+
exit 1
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
# The "main function"
|
387
|
+
if @scriptopts.show != [] then
|
388
|
+
show_scheme
|
389
|
+
end
|
390
|
+
if @scriptopts.writeconf then
|
391
|
+
write_configfile
|
392
|
+
end
|
393
|
+
if ! (@scriptopts.contentfile.nil? and @issueopts.content.nil?) then # If there is no content set it makes no sense to try to build a ticket
|
394
|
+
content = prepare_new_ticket
|
395
|
+
exit create_new_ticket(content)
|
396
|
+
end
|
397
|
+
|