trac4r 1.1.0 → 1.2.1
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/.gitignore +5 -0
- data/LICENCE +42 -0
- data/README.rdoc +16 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/bin/trac +289 -0
- data/lib/trac4r/error.rb +14 -6
- data/lib/trac4r/query.rb +1 -5
- data/lib/trac4r/ticket.rb +8 -1
- data/lib/trac4r/tickets.rb +27 -5
- data/lib/trac4r/wiki.rb +5 -0
- data/lib/trac4r.rb +9 -3
- metadata +40 -13
data/LICENCE
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Copyright (c) 2008 Niklas E. Cathor <niklas@brueckenschlaeger.de>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
4
|
+
copy of this software and associated documentation files (the "Software"),
|
5
|
+
to deal in the Software without restriction, including without limitation
|
6
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
7
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
8
|
+
Software is furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
Copyright (c) 2008 Niklas E. Cathor <niklas@brueckenschlaeger.de>
|
25
|
+
|
26
|
+
Hiermit wird unentgeltlich, jeder Person, die eine Kopie der Software und
|
27
|
+
der zugeh�rigen Dokumentationen (die "Software") erh�lt, die Erlaubnis
|
28
|
+
erteilt, uneingeschr�nkt zu benutzen, inklusive und ohne au�nahme, dem
|
29
|
+
Recht, sie zu verwenden, kopieren, �ndern, fusionieren, verlegen, verbreiten,
|
30
|
+
unterlizenzieren und/oder zu verkaufen, und Personen, die diese Software
|
31
|
+
erhalten, diese Rechte zu geben, unter den folgenden Bedingungen:
|
32
|
+
|
33
|
+
Der obige Urheberrechtsvermerk und dieser Erlaubnisvermerk sind in alle
|
34
|
+
Kopien oder Teilkopien der Software beizulegen.
|
35
|
+
|
36
|
+
DIE SOFTWARE WIRD OHNE JEDE AUSDR�CKLICHE ODER IMPLIZIERTE GARANTIE BEREITGE-
|
37
|
+
STELLT, EINSCHIESSLICH DER GARANTIE ZUR BENUTZUNG F�R DEN VORGESEHENEN ODER
|
38
|
+
EINEM BESTIMMTEN ZWECK SOWIE JEGLICHER RECHTSVERLETZUNG, JEDOCH NICHT DARAUF
|
39
|
+
BESCHR�NKT. IN KEINEM FALL SIND DIE AUTOREN ODER COPYRIGHTINHABER F�R
|
40
|
+
JEGLICHEN SCHADEN ODER SONSTIGE ANSPRUCH HAFTBAR ZU MACHEN, OB INFOLGE DER
|
41
|
+
ERF�LLUNG VON EINEM VERTRAG, EINEM DELIKT ODER ANDERS IM ZUSAMMENHANG MIT
|
42
|
+
DER BENUTZUNG ODER SONSTIGE VERWENDUNG DER SOFTWARE ENTSTANDEN.
|
data/README.rdoc
CHANGED
@@ -2,6 +2,7 @@ trac4r: Ruby wrapper for the Trac XML-RPC API
|
|
2
2
|
=============================================
|
3
3
|
|
4
4
|
Author:: Niklas Cathor
|
5
|
+
Author:: David Copeland
|
5
6
|
License:: See LICENSE in source distribution
|
6
7
|
|
7
8
|
For more information on the Trac XML-RPC see the {plugin's page on trac-hacks.com}[http://trac-hacks.org/wiki/XmlRpcPlugin#UsingfromRuby]
|
@@ -29,6 +30,21 @@ This wraps the Trac XML-RPC plugin.
|
|
29
30
|
trac.tickets.list # get all tickets
|
30
31
|
trac.tickets.get 2334 # Get ticket #2334
|
31
32
|
|
33
|
+
=== Tickets
|
34
|
+
|
35
|
+
Trac's backbone is tickets. The Tickets class contains many useful methods, but can also run arbitrary queries against Trac using
|
36
|
+
a more Rubyesque syntax:
|
37
|
+
|
38
|
+
# Gets all tickets in the "Web" component with a status of either "assigned"
|
39
|
+
# "accepted", or "new"
|
40
|
+
available_web_tickets = trac.tickets.query(:component => 'Web', :status => [:assigned,:accepted,:new])
|
41
|
+
|
42
|
+
# Ticktes that are not closed
|
43
|
+
unclosed_tickets = trac.tickets.query(:status => "!closed")
|
44
|
+
|
45
|
+
# This is a bit wierd, the "!" in the first element means "none of these values"
|
46
|
+
not_closed_nor_testing = trac.tickets.query(:status => ["!closed","test"])
|
47
|
+
|
32
48
|
== More Info
|
33
49
|
|
34
50
|
* {RDoc}[http://davetron5000.github.com/trac4r]
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'hanna/rdoctask'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
$: << '../grancher/lib'
|
7
|
+
begin
|
8
|
+
require 'grancher/task'
|
9
|
+
Grancher::Task.new do |g|
|
10
|
+
g.branch = 'gh-pages'
|
11
|
+
g.push_to = 'origin'
|
12
|
+
g.directory 'html'
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
#puts "you may install the optional gem 'grancher'"
|
16
|
+
end
|
17
|
+
|
18
|
+
begin
|
19
|
+
require 'jeweler'
|
20
|
+
Jeweler::Tasks.new do |s|
|
21
|
+
s.name = "trac4r"
|
22
|
+
s.executables = "trac"
|
23
|
+
s.summary = 'Ruby Client Library for Trac'
|
24
|
+
s.email = "davidcopeland@naildrivin5.com"
|
25
|
+
s.description = 'Basic ruby client library and command line interface for accessing Trac instances via its XML RPC API'
|
26
|
+
s.authors = ['Niklas Cathro','David Copeland']
|
27
|
+
s.add_dependency('rainbow', '>= 1.0.4')
|
28
|
+
s.add_dependency('gli', '>= 1.1.0')
|
29
|
+
s.has_rdoc = true
|
30
|
+
s.extra_rdoc_files = ['README.rdoc']
|
31
|
+
s.rdoc_options << '--title' << 'trac4r Trac Ruby Client' << '--main' << 'README.rdoc' << '-ri'
|
32
|
+
s.require_paths << 'lib'
|
33
|
+
end
|
34
|
+
Jeweler::GemcutterTasks.new
|
35
|
+
rescue LoadError
|
36
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::RDocTask.new do |rd|
|
40
|
+
rd.main = "README.rdoc"
|
41
|
+
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
42
|
+
rd.title = 'Ruby interface to Trac'
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default => :test
|
46
|
+
|
47
|
+
task :publish_rdoc => [:rdoc,:publish]
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.2.1
|
data/bin/trac
ADDED
@@ -0,0 +1,289 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
3
|
+
require 'rubygems'
|
4
|
+
require 'gli'
|
5
|
+
require 'trac4r'
|
6
|
+
require 'rainbow'
|
7
|
+
require 'cgi'
|
8
|
+
|
9
|
+
include GLI
|
10
|
+
|
11
|
+
OPENER_DEFAULT = RUBY_PLATFORM =~ /darwin/ ? 'open' : nil
|
12
|
+
begin
|
13
|
+
# TODO: Figure out a better way to do this
|
14
|
+
cols = `stty -a | grep "columns;" | head -1`.split(/;/)
|
15
|
+
COLUMNS_DEFAULT = cols[2].gsub(' columns','')
|
16
|
+
rescue
|
17
|
+
COLUMNS_DEFAULT = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
config_file '.trac4r'
|
21
|
+
|
22
|
+
desc 'Command to use to open URLs'
|
23
|
+
default_value OPENER_DEFAULT
|
24
|
+
flag [:o,:open]
|
25
|
+
|
26
|
+
desc 'URL to trac'
|
27
|
+
flag [:url]
|
28
|
+
|
29
|
+
desc 'Your username'
|
30
|
+
flag [:u,:user]
|
31
|
+
|
32
|
+
desc 'Your password'
|
33
|
+
flag [:p,:password]
|
34
|
+
|
35
|
+
desc 'Do not format output'
|
36
|
+
long_desc 'By default, the output is formatted fo readability in the terminal. By disabling this, the output is more "machine readable" and parsable by other scripts'
|
37
|
+
switch [:noformat]
|
38
|
+
|
39
|
+
desc 'number of columns for formatting'
|
40
|
+
default_value COLUMNS_DEFAULT
|
41
|
+
flag [:cols]
|
42
|
+
|
43
|
+
desc 'Open the ticket or wiki page'
|
44
|
+
arg_name 'the id of the ticket or name of wiki page'
|
45
|
+
command :open do |c|
|
46
|
+
c.action do |global_options,options,args|
|
47
|
+
raise "You must supply a ticket ID or WikiName" if args.empty?
|
48
|
+
id = args[0]
|
49
|
+
if id =~ /^\d+$/
|
50
|
+
system "#{global_options[:o]} #{$url}/ticket/#{id}"
|
51
|
+
else
|
52
|
+
system "#{global_options[:o]} #{$url}/wiki/#{args.map{ |x| x[0..0].upcase + x[1..-1]}.join('')}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
desc 'Go to the new ticket web interface'
|
58
|
+
long_desc 'Navigates your browser to the web interface, initialized with the values you provide, but does not actually create the ticket'
|
59
|
+
arg_name 'summary for the ticket'
|
60
|
+
command [:newticket] do |c|
|
61
|
+
c.desc 'component'
|
62
|
+
c.flag [:c,:component]
|
63
|
+
|
64
|
+
c.desc 'type'
|
65
|
+
c.flag [:t,:type]
|
66
|
+
|
67
|
+
c.desc 'priority'
|
68
|
+
c.flag [:p,:priority]
|
69
|
+
|
70
|
+
c.action do |global_options,options,args|
|
71
|
+
query_params = {}
|
72
|
+
query_params['priority'] = options[:p] if options[:p]
|
73
|
+
query_params['component'] = options[:c] if options[:c]
|
74
|
+
query_params['type'] = options[:t] if options[:t]
|
75
|
+
query_params['summary'] = args.join(' ')
|
76
|
+
query_string = ''
|
77
|
+
query_params.each do |key,value|
|
78
|
+
query_string += key
|
79
|
+
query_string += '='
|
80
|
+
query_string += CGI.escape(value)
|
81
|
+
query_string += '&'
|
82
|
+
end
|
83
|
+
|
84
|
+
url = $url.gsub(/\/xmlrpc/,'') + '/newticket?' + query_string
|
85
|
+
system "#{global_options[:o]} \"#{url}\""
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
FORMATTING = {
|
90
|
+
'id' => { :color => :green, :size => 6 },
|
91
|
+
'status' => { :color => :cyan, :size => 9 },
|
92
|
+
'owner' => { :size => 17 },
|
93
|
+
'component' => { :size => 10, :color => :magenta },
|
94
|
+
'milestone' => { :size => 28, :color => :cyan },
|
95
|
+
}
|
96
|
+
desc 'Lists tickets'
|
97
|
+
arg_name 'ticket ids (blank for all)'
|
98
|
+
command [:tickets,:ls] do |c|
|
99
|
+
c.desc 'Show tickets accepted'
|
100
|
+
c.switch [:a,:accepted]
|
101
|
+
|
102
|
+
c.desc 'Component'
|
103
|
+
c.flag [:c,:component]
|
104
|
+
|
105
|
+
c.desc 'Show full description'
|
106
|
+
c.switch [:l,:description]
|
107
|
+
|
108
|
+
c.desc 'Arbitrary query (flags are included, too)'
|
109
|
+
c.flag [:q,:query]
|
110
|
+
|
111
|
+
c.desc 'Owner ("ME" for the -u user)'
|
112
|
+
c.flag [:o,:owner]
|
113
|
+
|
114
|
+
c.desc 'Columns to show'
|
115
|
+
c.long_desc 'comma-delimited list of the column names from the tickets to show in the output'
|
116
|
+
c.flag [:columns]
|
117
|
+
|
118
|
+
c.action do |global_options,options,args|
|
119
|
+
opts = {}
|
120
|
+
|
121
|
+
if options[:q]
|
122
|
+
raise "bad query" if options[:q] =~ /\}/
|
123
|
+
opts = instance_eval('{' + options[:q] + '}')
|
124
|
+
else
|
125
|
+
opts[:owner] = options[:o]
|
126
|
+
opts[:owner] = global_options[:u] if options[:o] == "ME"
|
127
|
+
if options[:a]
|
128
|
+
opts[:status] = :accepted
|
129
|
+
else
|
130
|
+
opts[:status] = ["!closed","testing"]
|
131
|
+
end
|
132
|
+
opts[:component] = options[:c] if options[:c]
|
133
|
+
end
|
134
|
+
ids = args
|
135
|
+
ids = $trac.tickets.query(opts) if ids.empty?
|
136
|
+
tickets = ids.map{ |id| $trac.tickets.get(id) }
|
137
|
+
tickets.sort{ |a,b| a.summary.downcase <=> b.summary.downcase }.each do |ticket|
|
138
|
+
if global_options[:noformat]
|
139
|
+
puts [ticket.id,ticket.status,ticket.owner,ticket.summary].join("\t")
|
140
|
+
else
|
141
|
+
columns = options[:columns]
|
142
|
+
columns = 'id,status,owner,summary' if !columns
|
143
|
+
columns = columns.split(/,/)
|
144
|
+
printf_string = ""
|
145
|
+
padding = 0
|
146
|
+
args = []
|
147
|
+
columns.each do |col|
|
148
|
+
if col != 'summary'
|
149
|
+
size = FORMATTING[col] && FORMATTING[col][:size]
|
150
|
+
size = 10 if !size
|
151
|
+
padding += size == "" ? 3 : (size.to_i + 3)
|
152
|
+
size += 9 if size && FORMATTING[col] && FORMATTING[col][:color]
|
153
|
+
printf_string += "%#{size}s - "
|
154
|
+
if FORMATTING[col] && FORMATTING[col][:color]
|
155
|
+
args << ticket.send(col.to_sym).to_s.color(FORMATTING[col][:color])
|
156
|
+
else
|
157
|
+
args << ticket.send(col.to_sym).to_s
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
printf_string.gsub!(/ - $/,'')
|
162
|
+
if columns.include? 'summary'
|
163
|
+
args << wrap(ticket.summary,padding+1,global_options[:cols])
|
164
|
+
printf_string += " - %s"
|
165
|
+
end
|
166
|
+
printf("#{printf_string}\n",*args)
|
167
|
+
end
|
168
|
+
if (options[:l])
|
169
|
+
description = ticket.description
|
170
|
+
if !global_options[:noformat]
|
171
|
+
description = bold(description)
|
172
|
+
description = italic(description)
|
173
|
+
description = code(description)
|
174
|
+
end
|
175
|
+
puts
|
176
|
+
puts "#{description}"
|
177
|
+
puts "----"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Not sure about this
|
184
|
+
def wrap(string,indent,cols)
|
185
|
+
cols_left = cols.to_i - indent
|
186
|
+
raise "Your terminal is too small for formatting" if (cols_left < 5)
|
187
|
+
return_me = ""
|
188
|
+
line = ""
|
189
|
+
prev_word = ""
|
190
|
+
string.split(/\s/).each do |word|
|
191
|
+
if line.length <= cols_left
|
192
|
+
line += " #{word}" if line != ""
|
193
|
+
line += "#{word}" if line == ""
|
194
|
+
prev_word = word
|
195
|
+
else
|
196
|
+
line.gsub!(/#{prev_word}$/,'')
|
197
|
+
return_me += line.underline + "\n"
|
198
|
+
indent.times { return_me += " " }
|
199
|
+
line = prev_word
|
200
|
+
end
|
201
|
+
end
|
202
|
+
if (line.length > cols_left)
|
203
|
+
line.gsub!(/#{prev_word}$/,'')
|
204
|
+
return_me += line.underline + "\n"
|
205
|
+
indent.times { return_me += " " }
|
206
|
+
line = prev_word
|
207
|
+
end
|
208
|
+
return_me += line.underline
|
209
|
+
return_me.gsub(/^\s/,'')
|
210
|
+
end
|
211
|
+
|
212
|
+
def bold(string)
|
213
|
+
desc = string.split("'''")
|
214
|
+
description = ""
|
215
|
+
bold = false
|
216
|
+
desc.each do |part|
|
217
|
+
description << part.bright.foreground(:cyan) if bold
|
218
|
+
description << part.reset if !bold
|
219
|
+
bold = !bold
|
220
|
+
end
|
221
|
+
description
|
222
|
+
end
|
223
|
+
|
224
|
+
def italic(string)
|
225
|
+
desc = string.split("''")
|
226
|
+
description = ""
|
227
|
+
bold = false
|
228
|
+
desc.each do |part|
|
229
|
+
description << part.italic.foreground(:magenta) if bold
|
230
|
+
description << part.reset if !bold
|
231
|
+
bold = !bold
|
232
|
+
end
|
233
|
+
description
|
234
|
+
end
|
235
|
+
|
236
|
+
def code(string)
|
237
|
+
desc = string.split("`")
|
238
|
+
description = ""
|
239
|
+
bold = false
|
240
|
+
desc.each do |part|
|
241
|
+
description << part.bright.foreground(:green) if bold
|
242
|
+
description << part.reset if !bold
|
243
|
+
bold = !bold
|
244
|
+
end
|
245
|
+
in_code = false
|
246
|
+
coded = ''
|
247
|
+
description.split(/\n/).each do |line|
|
248
|
+
ignore = false
|
249
|
+
if line =~ /^\{\{\{\s*$/
|
250
|
+
in_code = true
|
251
|
+
ignore = true
|
252
|
+
elsif line =~ /^\}\}\}/
|
253
|
+
in_code = false
|
254
|
+
ignore = true
|
255
|
+
end
|
256
|
+
if !ignore
|
257
|
+
if in_code
|
258
|
+
coded += line.bright.foreground(:green)
|
259
|
+
else
|
260
|
+
coded += line
|
261
|
+
end
|
262
|
+
end
|
263
|
+
coded += "\n"
|
264
|
+
end
|
265
|
+
coded
|
266
|
+
end
|
267
|
+
|
268
|
+
pre do |global,command,options,args|
|
269
|
+
if command.nil? || command.name == :help
|
270
|
+
# not creating a trac instance
|
271
|
+
else
|
272
|
+
$url = global[:url]
|
273
|
+
raise "You must specify a URL" if $url.nil?
|
274
|
+
$trac = Trac.new($url,global[:u],global[:p])
|
275
|
+
end
|
276
|
+
true
|
277
|
+
end
|
278
|
+
|
279
|
+
post do |global,command,options,args|
|
280
|
+
# Post logic here
|
281
|
+
end
|
282
|
+
|
283
|
+
on_error do |exception|
|
284
|
+
# Error logic here
|
285
|
+
# return false to skip default error handling
|
286
|
+
true
|
287
|
+
end
|
288
|
+
|
289
|
+
GLI.run(ARGV)
|
data/lib/trac4r/error.rb
CHANGED
@@ -8,22 +8,28 @@ module Trac
|
|
8
8
|
# [+path+] the path to the Trac API
|
9
9
|
# [+method+] the XML RPC method being called
|
10
10
|
# [+args+] the args (as an array) that were sent with the call
|
11
|
-
|
12
|
-
|
13
|
-
if http_error =~
|
14
|
-
http_error.
|
11
|
+
# [+exception+] the exception that was caught
|
12
|
+
def initialize(http_error,host,port,path,method,args,exception)
|
13
|
+
if (http_error =~ /HTTP-Error: /)
|
14
|
+
http_error = http_error.sub 'HTTP-Error: ',''
|
15
|
+
if http_error =~ /\n/
|
16
|
+
http_error.split(/\n/).each do |line|
|
15
17
|
if line =~ /^\d\d\d/
|
16
18
|
http_error = line
|
17
19
|
break
|
18
20
|
end
|
21
|
+
end
|
19
22
|
end
|
23
|
+
@http_status,@http_message = http_error.split(/\s+/,2)
|
24
|
+
else
|
25
|
+
@http_message = http_error
|
20
26
|
end
|
21
|
-
@http_status,@http_message = http_error.split(/\s+/,2)
|
22
27
|
@host = host
|
23
28
|
@port = port
|
24
29
|
@path = path
|
25
30
|
@method = method
|
26
31
|
@args = args
|
32
|
+
@exception = exception
|
27
33
|
end
|
28
34
|
|
29
35
|
# Gives a more useful message for common problems
|
@@ -32,8 +38,10 @@ module Trac
|
|
32
38
|
"Couldn't find Trac API at #{url}, check your configuration"
|
33
39
|
elsif @http_status == '401'
|
34
40
|
"Your username/password didn't authenticate, check your configuration"
|
41
|
+
elsif @http_status
|
42
|
+
"#{@http_message} (#{@http_status}) when trying URL #{url} and method #{@method}(#{@args.join('.')})"
|
35
43
|
else
|
36
|
-
"#{@http_message}
|
44
|
+
"#{@http_message} when trying URL #{url} and method #{@method}(#{@args.join('.')})"
|
37
45
|
end
|
38
46
|
end
|
39
47
|
|
data/lib/trac4r/query.rb
CHANGED
@@ -50,11 +50,7 @@ module Trac
|
|
50
50
|
begin
|
51
51
|
return @connection.call(command,*args)
|
52
52
|
rescue => e
|
53
|
-
|
54
|
-
raise TracException.new(e.message,@host,@port,@path,command,args)
|
55
|
-
else
|
56
|
-
raise
|
57
|
-
end
|
53
|
+
raise TracException.new(e.message,@host,@port,@path,command,args,e)
|
58
54
|
end
|
59
55
|
end
|
60
56
|
end
|
data/lib/trac4r/ticket.rb
CHANGED
@@ -36,10 +36,17 @@ module Trac
|
|
36
36
|
# we return its value. e.g. if our tickets have a custom field
|
37
37
|
# called +work_units+, then +some_ticket.work_units+ will
|
38
38
|
# retrieve that value. This currently only allows retrieval and
|
39
|
-
# not updating the value.
|
39
|
+
# not updating the value. Also note that you can retrieve a custom
|
40
|
+
# field using "!" and this will silently return nil if the instance
|
41
|
+
# variable didn't exist. This is useful if some tickets just don't
|
42
|
+
# have the custom field, but you don't wish to check for it
|
40
43
|
def method_missing(sym,*args)
|
44
|
+
method = sym.to_s
|
45
|
+
method = method[0..-2] if method =~ /!$/
|
41
46
|
if args.size == 0 && instance_variables.include?("@" + sym.to_s)
|
42
47
|
instance_eval("@" + sym.to_s)
|
48
|
+
elsif method != sym.to_s
|
49
|
+
nil
|
43
50
|
else
|
44
51
|
super.method_missing(sym,args)
|
45
52
|
end
|
data/lib/trac4r/tickets.rb
CHANGED
@@ -34,15 +34,25 @@ module Trac
|
|
34
34
|
# list :include_closed => false
|
35
35
|
# to only get open tickets.
|
36
36
|
def list options={ }
|
37
|
-
include_closed =
|
38
|
-
|
39
|
-
tickets
|
37
|
+
include_closed = true
|
38
|
+
include_closed = options[:include_closed] if !options[:include_closed].nil?
|
39
|
+
tickets = query(:status => "!closed")
|
40
|
+
tickets += query(:status => "closed") if include_closed
|
40
41
|
return tickets
|
41
42
|
end
|
42
|
-
|
43
|
+
|
44
|
+
# Run an arbitrary ticket query
|
45
|
+
# [+args+] a hash of options, each should use a symbol or string
|
46
|
+
# as the key and a symbol/string or array of symbols/strings as the value. If the
|
47
|
+
# value starts with a +!+, it will be treated as a not equal.
|
48
|
+
# Multiple values mean "or", as in any value may match
|
49
|
+
def query(args)
|
50
|
+
@trac.query("ticket.query",args_to_trac_args(args))
|
51
|
+
end
|
52
|
+
|
43
53
|
# like `list', but only gets closed tickets
|
44
54
|
def list_closed
|
45
|
-
|
55
|
+
query(:status => "closed")
|
46
56
|
end
|
47
57
|
|
48
58
|
# returns all tickets (not just the ids) in a hash
|
@@ -155,5 +165,17 @@ module Trac
|
|
155
165
|
end
|
156
166
|
return @settings
|
157
167
|
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
def args_to_trac_args(args)
|
172
|
+
trac_args = []
|
173
|
+
args.each do |key,value|
|
174
|
+
value = [value].flatten.map{ |x| x.to_s }.join('|')
|
175
|
+
trac_args << key.to_s + (value =~ /^!/ ? "!=#{value[1..-1]}" : "=#{value}")
|
176
|
+
end
|
177
|
+
trac_args.join('&')
|
178
|
+
end
|
179
|
+
|
158
180
|
end
|
159
181
|
end
|
data/lib/trac4r/wiki.rb
CHANGED
@@ -44,6 +44,11 @@ module Trac
|
|
44
44
|
@trac.query('wiki.getPageHTML',name)
|
45
45
|
end
|
46
46
|
|
47
|
+
# returns a whole page in HTML
|
48
|
+
def get_info name
|
49
|
+
@trac.query('wiki.getPageInfo',name)
|
50
|
+
end
|
51
|
+
|
47
52
|
# returns a whole page in raw format
|
48
53
|
def get_raw name
|
49
54
|
@trac.query('wiki.getPage',name)
|
data/lib/trac4r.rb
CHANGED
@@ -64,13 +64,19 @@ module Trac
|
|
64
64
|
def initialize url,user,pass
|
65
65
|
@user = user
|
66
66
|
@pass = pass
|
67
|
-
|
68
|
-
|
67
|
+
@url = url
|
68
|
+
@url.gsub!(/\/$/,'')
|
69
|
+
if @url.split('/').last != 'xmlrpc'
|
70
|
+
@url = url+'/xmlrpc'
|
69
71
|
end
|
70
|
-
|
72
|
+
@connection = Query.new(@url,@user,@pass)
|
71
73
|
@wiki = Wiki.new(@connection)
|
72
74
|
@tickets = Tickets.new(@connection)
|
73
75
|
end
|
76
|
+
|
77
|
+
def query(command,*args)
|
78
|
+
@connection.query(command,*args)
|
79
|
+
end
|
74
80
|
|
75
81
|
def api_version
|
76
82
|
@connection.query("system.getAPIVersion")
|
metadata
CHANGED
@@ -1,40 +1,66 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trac4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Niklas Cathro
|
8
|
+
- David Copeland
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date:
|
13
|
-
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
date: 2010-01-03 00:00:00 -05:00
|
14
|
+
default_executable: trac
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rainbow
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.0.4
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: gli
|
28
|
+
type: :runtime
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.1.0
|
35
|
+
version:
|
36
|
+
description: Basic ruby client library and command line interface for accessing Trac instances via its XML RPC API
|
37
|
+
email: davidcopeland@naildrivin5.com
|
38
|
+
executables:
|
39
|
+
- trac
|
20
40
|
extensions: []
|
21
41
|
|
22
42
|
extra_rdoc_files:
|
23
43
|
- README.rdoc
|
24
44
|
files:
|
45
|
+
- .gitignore
|
46
|
+
- LICENCE
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
49
|
+
- VERSION
|
50
|
+
- bin/trac
|
51
|
+
- lib/trac4r.rb
|
25
52
|
- lib/trac4r/error.rb
|
26
53
|
- lib/trac4r/query.rb
|
27
54
|
- lib/trac4r/ticket.rb
|
28
55
|
- lib/trac4r/tickets.rb
|
29
56
|
- lib/trac4r/wiki.rb
|
30
|
-
- lib/trac4r.rb
|
31
|
-
- README.rdoc
|
32
57
|
has_rdoc: true
|
33
|
-
homepage:
|
58
|
+
homepage:
|
34
59
|
licenses: []
|
35
60
|
|
36
61
|
post_install_message:
|
37
62
|
rdoc_options:
|
63
|
+
- --charset=UTF-8
|
38
64
|
- --title
|
39
65
|
- trac4r Trac Ruby Client
|
40
66
|
- --main
|
@@ -43,6 +69,7 @@ rdoc_options:
|
|
43
69
|
require_paths:
|
44
70
|
- lib
|
45
71
|
- lib
|
72
|
+
- lib
|
46
73
|
required_ruby_version: !ruby/object:Gem::Requirement
|
47
74
|
requirements:
|
48
75
|
- - ">="
|
@@ -57,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
84
|
version:
|
58
85
|
requirements: []
|
59
86
|
|
60
|
-
rubyforge_project:
|
87
|
+
rubyforge_project:
|
61
88
|
rubygems_version: 1.3.5
|
62
89
|
signing_key:
|
63
90
|
specification_version: 3
|