trac4r 1.0.0

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/README.rdoc ADDED
@@ -0,0 +1,35 @@
1
+ trac4r: Ruby wrapper for the Trac XML-RPC API
2
+ =============================================
3
+
4
+ Author:: Niklas Cathor
5
+ License:: See LICENSE in source distribution
6
+
7
+ For more information on the Trac XML-RPC see the {plugin's page on trac-hacks.com}[http://trac-hacks.org/wiki/XmlRpcPlugin#UsingfromRuby]
8
+
9
+ Thanks to the original author, Niklas Cathor, who has done most of the work.
10
+
11
+ == Install
12
+
13
+ # Only if you haven't set up gemcutter yet
14
+ sudo gem install gemcutter
15
+ sudo gem tumble
16
+
17
+ # Once Gemcutter is setup
18
+ sudo gem install trac4r
19
+
20
+ == Overview
21
+
22
+ This wraps the Trac XML-RPC plugin.
23
+
24
+ require 'rubygems'
25
+ require 'trac4r'
26
+
27
+ # Note that you need to point to the XMLRPC root and not the root of the trac web interface
28
+ trac = Trac.new("http://www.example.com/trac/project/xmlrpc","username","password")
29
+ trac.tickets.list # get all tickets
30
+ trac.tickets.get 2334 # Get ticket #2334
31
+
32
+ == More Info
33
+
34
+ * {RDoc}[http://davetron5000.github.com/trac4r]
35
+ * {Source}[http://www.github.com/davetron5000/trac4r]
@@ -0,0 +1,44 @@
1
+ module Trac
2
+ class TracException < Exception
3
+ # Creates new TracException
4
+ #
5
+ # [+http_error+] the error message, possibly mulit-line
6
+ # [+host+] host on which we are connecting to Trac
7
+ # [+port+] port we're using
8
+ # [+path+] the path to the Trac API
9
+ # [+method+] the XML RPC method being called
10
+ # [+args+] the args (as an array) that were sent with the call
11
+ def initialize(http_error,host,port,path,method,args)
12
+ http_error = http_error.sub 'HTTP-Error: ',''
13
+ if http_error =~ /\n/
14
+ http_error.split(/\n/).each do |line|
15
+ if line =~ /^\d\d\d/
16
+ http_error = line
17
+ break
18
+ end
19
+ end
20
+ end
21
+ @http_status,@http_message = http_error.split(/\s+/,2)
22
+ @host = host
23
+ @port = port
24
+ @path = path
25
+ @method = method
26
+ @args = args
27
+ end
28
+
29
+ # Gives a more useful message for common problems
30
+ def message
31
+ if @http_status == '404'
32
+ "Couldn't find Trac API at #{url}, check your configuration"
33
+ elsif @http_status == '401'
34
+ "Your username/password didn't authenticate, check your configuration"
35
+ else
36
+ "#{@http_message} (#{@http_status}) when trying URL http://#{@host}:#{@port}#{@path} and method #{@command}(#{@args.join('.')})"
37
+ end
38
+ end
39
+
40
+ def url
41
+ "http://#{@host}:#{@port}#{@path}"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,62 @@
1
+ =begin
2
+ Copyright (c) 2008 Niklas E. Cathor <niklas@brueckenschlaeger.de>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a
5
+ copy of this software and associated documentation files (the "Software"),
6
+ to deal in the Software without restriction, including without limitation
7
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ and/or sell copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
22
+ DON'T USE IT IF YOU'RE AN ASSHOLE!
23
+ =end
24
+
25
+ require 'xmlrpc/client'
26
+
27
+ module Trac
28
+ class Query
29
+ def initialize url,user,pass
30
+ if user && pass
31
+ url = url.sub 'xmlrpc','login/xmlrpc'
32
+ end
33
+ uri = URI.parse(url)
34
+ use_ssl = (uri.scheme == 'https') ? true : false
35
+ @host = uri.host
36
+ @path = uri.path
37
+ @port = uri.port
38
+ @connection = XMLRPC::Client.new(@host,
39
+ @path,
40
+ @port,
41
+ nil,
42
+ nil,
43
+ user,
44
+ pass,
45
+ use_ssl,
46
+ nil)
47
+ end
48
+
49
+ def query command, *args
50
+ begin
51
+ return @connection.call(command,*args)
52
+ rescue => e
53
+ if e.message =~ /HTTP-Error/
54
+ errorcode = e.message.sub 'HTTP-Error: ',''
55
+ raise TracException.new(errorcode,@host,@port,@path,command,args)
56
+ else
57
+ raise
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,45 @@
1
+ module Trac
2
+ # This class represents a ticket as it is retrieved from the database
3
+ class Ticket
4
+ attr_accessor(:id, # Integer
5
+ :severity, # String
6
+ :milestone, # String
7
+ :status, # String
8
+ :type, # String
9
+ :priority, # String
10
+ :version, # String
11
+ :reporter, # String
12
+ :owner, # String
13
+ :cc, # String
14
+ :summary, # String
15
+ :description, # String
16
+ :keywords, # String
17
+ :created_at, # XMLRPC::DateTime
18
+ :updated_at) # XMLRPC::DateTime
19
+ # returns a new ticket
20
+ def initialize id=0
21
+ @id = id
22
+ @severity=@milestone=@status=@type=@priority=@version=@reporter=@owner= @cc= @summary=@description=@keywords=""
23
+ end
24
+
25
+ # checks if all attributes are set
26
+ def check
27
+ instance_variables.each do |v|
28
+ return false if instance_variable_get(v.to_sym).nil?
29
+ end
30
+ return true
31
+ end
32
+
33
+ # loads a ticket from the XMLRPC response
34
+ def self.load params
35
+ ticket = self.new params[0]
36
+ ticket.created_at = params[1]
37
+ ticket.updated_at = params[2]
38
+ attributes = params[3]
39
+ attributes.each do |key,value|
40
+ ticket.instance_variable_set("@#{key}".to_sym,value)
41
+ end
42
+ return ticket
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,159 @@
1
+ =begin
2
+ Copyright (c) 2008 Niklas E. Cathor <niklas@brueckenschlaeger.de>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a
5
+ copy of this software and associated documentation files (the "Software"),
6
+ to deal in the Software without restriction, including without limitation
7
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ and/or sell copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
22
+
23
+ DON'T USE IT IF YOU'RE AN ASSHOLE!
24
+ =end
25
+
26
+ module Trac
27
+ class Tickets
28
+ def initialize trac
29
+ @trac = trac
30
+ end
31
+
32
+ # returns a list of all tickets (the ids), by performing two
33
+ # queries, one for closed tickets, one for opened. use
34
+ # list :include_closed => false
35
+ # to only get open tickets.
36
+ def list options={ }
37
+ include_closed = options[:include_closed] || true
38
+ tickets = @trac.query("ticket.query","status!=closed")
39
+ tickets += @trac.query("ticket.query","status=closed") if include_closed
40
+ return tickets
41
+ end
42
+
43
+ # like `list', but only gets closed tickets
44
+ def list_closed
45
+ @trac.query("ticket.query","status=closed")
46
+ end
47
+
48
+ # returns all tickets (not just the ids) in a hash
49
+ # warning: to avoid heavy traffic load the results are cached
50
+ # and will only be updated after 5 minutes. use
51
+ # get_all :cached_results => false
52
+ # to avoid this.
53
+ # other options:
54
+ # :include_closed - see Tickets#list for a description
55
+ def get_all options={ }
56
+ include_closed = options[:include_closed] || true
57
+ cached_results = options[:cached_results] || true
58
+ if(cached_results == true &&
59
+ @cache_last_update &&
60
+ @cache_last_update > Time.now - 300)
61
+ return @cache
62
+ end
63
+ tickets = { }
64
+ list(:include_closed => include_closed).each do |ticket|
65
+ tickets[ticket] = get ticket
66
+ end
67
+ @cache = tickets
68
+ @cache_last_update = Time.now
69
+ return tickets
70
+ end
71
+
72
+ # fetch a ticket. Returns instance of Trac::Ticket
73
+ def get id
74
+ Ticket.load @trac.query("ticket.get",id)
75
+ end
76
+
77
+ # create a new ticket returning the ticket id
78
+ def create summary,description,attributes={ },notify=false
79
+ @trac.query("ticket.create",summary,description,attributes,notify)
80
+ end
81
+
82
+ # update ticket returning the ticket in the same orm as ticket.get
83
+ def update id,comment,attributes={ },notify=false
84
+ attr = {}
85
+ attributes.each_pair do |key, value|
86
+ unless(value.nil? || value.size == 0 || value.empty?)
87
+ attr[key] = value
88
+ end
89
+ end
90
+ @trac.query("ticket.update",id,comment,attr,notify)
91
+ end
92
+
93
+ # delete ticket by id
94
+ def delete id
95
+ @trac.query("ticket.delete",id)
96
+ end
97
+
98
+ # return the changelog as a list of tuples of the form (time,author,
99
+ # field,oldvalue,newvalue,permanent). While the other tuples elements
100
+ # are quite self-explanatory, the permanent flag is used to distinguish
101
+ # collateral changes that are not yet immutable (like attachments,
102
+ # currently).
103
+ def changelog ticket_id,w=0
104
+ @trac.query("ticket.changeLog",ticket_id,w)
105
+ end
106
+
107
+ # returns a list of ids of tickets that have changed since `time'
108
+ def changes time
109
+ @trac.query("ticket.getRecentChanges",time)
110
+ end
111
+
112
+ # returns a list of attachments for the given ticket
113
+ def attachments ticket_id
114
+ @trac.query("ticket.listAttachments",ticket_id)
115
+ end
116
+
117
+ # returns the content of an attachment
118
+ def get_attachment ticket_id,filename
119
+ @trac.query("ticket.getAttachment",ticket_id,filename)
120
+ end
121
+
122
+ # adds an attachment to a ticket
123
+ def put_attachment ticket_id,filename,description,data,replace=true
124
+ @trac.query("ticket.putAttachment",ticket_id,filename,description,data,replace)
125
+ end
126
+
127
+ # deletes given attachment
128
+ def delete_attachment ticket_id,filename
129
+ @trac.query("ticket.deleteAttachment",ticket_id,filename)
130
+ end
131
+
132
+ # returns the actions that can be performed on the ticket
133
+ def actions ticket_id
134
+ @trac.query("ticket.getAvailableActions",ticket_id)
135
+ end
136
+
137
+
138
+ # returns all settings (possible values for status, version,
139
+ # priority, resolution, component, type, severity or milestone)
140
+ # as a hash in the form: { :status => ["assigned","closed",...], ... }
141
+ # this method only gets the settings once per session. To update
142
+ # them please refer to Tickets#get_settings
143
+ def settings
144
+ @settings || get_settings
145
+ end
146
+
147
+
148
+ # returns the settings in the same form as Tickets#settings, but
149
+ # refreshes them every time we call it.
150
+ def get_settings
151
+ @settings = { }
152
+ ['status','version','priority','resolution',
153
+ 'component','type','severity','milestone'].each do |setting|
154
+ @settings[setting.to_sym] = @trac.query("ticket.#{setting}.getAll")
155
+ end
156
+ return @settings
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,86 @@
1
+ =begin
2
+ Copyright (c) 2008 Niklas E. Cathor <niklas@brueckenschlaeger.de>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a
5
+ copy of this software and associated documentation files (the "Software"),
6
+ to deal in the Software without restriction, including without limitation
7
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ and/or sell copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
22
+
23
+ DON'T USE IT IF YOU'RE AN ASSHOLE!
24
+ =end
25
+
26
+ module Trac
27
+ class Wiki
28
+ def initialize trac
29
+ @trac = trac
30
+ end
31
+
32
+ # returns a list of all pages
33
+ def list
34
+ @trac.query('wiki.getAllPages')
35
+ end
36
+
37
+ # convert a raw page to html (e.g. for preview)
38
+ def raw_to_html content
39
+ @trac.query('wiki.wikiToHtml',content)
40
+ end
41
+
42
+ # returns a whole page in HTML
43
+ def get_html name
44
+ @trac.query('wiki.getPageHTML',name)
45
+ end
46
+
47
+ # returns a whole page in raw format
48
+ def get_raw name
49
+ @trac.query('wiki.getPage',name)
50
+ end
51
+
52
+ # sends a page. if the page doesn't exist yet it is created
53
+ # otherwise it will be overwritten with the new content.
54
+ def put name,content,attributes={ }
55
+ @trac.query('wiki.putPage',name,content,attributes)
56
+ end
57
+
58
+ # deletes page with given name, returning true on success.
59
+ def delete name
60
+ @trac.query('wiki.deletePage',name)
61
+ end
62
+
63
+ # returns a list of all attachments of a page
64
+ def attachments page
65
+ @trac.query("wiki.listAttachments",page)
66
+ end
67
+
68
+ # returns the content of an attachment
69
+ def get_attachment path
70
+ @trac.query("wiki.getAttachment",path)
71
+ end
72
+
73
+ # uploads given `data' as an attachment to given `page'.
74
+ # returns true on success.
75
+ # unlike the XMLRPC-Call this method defaults `replace'
76
+ # to false as we don't want to destroy anything.
77
+ def put_attachment page,filename,description,data,replace=false
78
+ @trac.query("wiki.putAttachmentEx",page,filename,description,data,replace)
79
+ end
80
+
81
+ # deletes attachment with given `path'
82
+ def delete_attachment path
83
+ @trac.query("wiki.deleteAttachment",path)
84
+ end
85
+ end
86
+ end
data/lib/trac4r.rb ADDED
@@ -0,0 +1,79 @@
1
+ =begin
2
+ Copyright (c) 2008 Niklas E. Cathor <niklas@brueckenschlaeger.de>
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a
5
+ copy of this software and associated documentation files (the "Software"),
6
+ to deal in the Software without restriction, including without limitation
7
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
+ and/or sell copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
22
+ DON'T USE IT IF YOU'RE AN ASSHOLE!
23
+ =end
24
+
25
+ filedir = File.dirname(__FILE__)
26
+
27
+ require "trac4r/query"
28
+ require "trac4r/tickets"
29
+ require "trac4r/ticket"
30
+ require "trac4r/wiki"
31
+ require "trac4r/error"
32
+
33
+
34
+ # This module wraps the XMLRPC interface of
35
+ # trac (http://trac.edgewall.org/) into a ruby library.
36
+ # You can now easily access trac from any ruby
37
+ # application without having to handle all the
38
+ # (trivial) XMLRPC calls.
39
+ #
40
+ # Example (receive list of opened tickets):
41
+ # require 'trac4r/trac'
42
+ # trac = Trac.new "http://dev.example.com/trac/my_awesome_project"
43
+ # trac.tickets.list :include_closed => false #=> [7,9,3,5,14,...]
44
+ #
45
+ # Receive one single ticket
46
+ # ticket = trac.tickets.get 9 #=> #<Trac::Ticket:0xb76de9b4 ... >
47
+ # ticket.summary #=> 'foo'
48
+ # ticket.description #=> 'bar'
49
+ # See documentation for Trac::Ticket for what methods you can call on ticket.
50
+ #
51
+ # Create a new ticket
52
+ # trac.tickets.create "summary", "description", :type => 'defect', :version => '1.0', :milestone => 'bug free' #=> 10
53
+ # summary and description are required, the rest is optional. It can be one of the following:
54
+ # :severity, :milestone, :status, :type, :priority, :version, :reporter, :owner, :cc, :keywords
55
+ #
56
+ module Trac
57
+ # returns a new instance of Trac::Base
58
+ def self.new url, user=nil,pass=nil
59
+ Base.new url,user,pass
60
+ end
61
+
62
+ class Base
63
+ attr_reader :wiki, :tickets, :user, :pass
64
+ def initialize url,user,pass
65
+ @user = user
66
+ @pass = pass
67
+ if url.split('/').last != 'xmlrpc'
68
+ url = url+'/xmlrpc'
69
+ end
70
+ @connection = Query.new(url,user,pass)
71
+ @wiki = Wiki.new(@connection)
72
+ @tickets = Tickets.new(@connection)
73
+ end
74
+
75
+ def api_version
76
+ @connection.query("system.getAPIVersion")
77
+ end
78
+ end
79
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trac4r
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Niklas Cathro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-20 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Basic ruby client library for accessing Trac instances via its XML RPC API
17
+ email:
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ files:
25
+ - lib/trac4r/error.rb
26
+ - lib/trac4r/query.rb
27
+ - lib/trac4r/ticket.rb
28
+ - lib/trac4r/tickets.rb
29
+ - lib/trac4r/wiki.rb
30
+ - lib/trac4r.rb
31
+ - README.rdoc
32
+ has_rdoc: true
33
+ homepage: http://github.com/csexton/trac4r/
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --title
39
+ - trac4r Trac Ruby Client
40
+ - --main
41
+ - README.rdoc
42
+ - -ri
43
+ require_paths:
44
+ - lib
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project: trac4r
61
+ rubygems_version: 1.3.5
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Ruby Client Library for Trac
65
+ test_files: []
66
+