meta_project 0.4.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/CHANGES +178 -0
- data/MIT-LICENSE +21 -0
- data/README +64 -0
- data/Rakefile +166 -0
- data/TODO +9 -0
- data/doc/base_attrs.rdoc +2 -0
- data/lib/meta_project/project/base.rb +7 -0
- data/lib/meta_project/project/codehaus/codehaus_project_svn.rb +26 -0
- data/lib/meta_project/project/codehaus.rb +1 -0
- data/lib/meta_project/project/trac/trac_project.rb +26 -0
- data/lib/meta_project/project/trac.rb +1 -0
- data/lib/meta_project/project/xforge/ruby_forge.rb +46 -0
- data/lib/meta_project/project/xforge/session.rb +162 -0
- data/lib/meta_project/project/xforge/source_forge.rb +46 -0
- data/lib/meta_project/project/xforge/xfile.rb +45 -0
- data/lib/meta_project/project/xforge/xforge_base.rb +76 -0
- data/lib/meta_project/project/xforge.rb +5 -0
- data/lib/meta_project/project.rb +4 -0
- data/lib/meta_project/project_analyzer.rb +36 -0
- data/lib/meta_project/scm_web.rb +53 -0
- data/lib/meta_project/tracker/base.rb +18 -0
- data/lib/meta_project/tracker/digit_issues.rb +24 -0
- data/lib/meta_project/tracker/issue.rb +11 -0
- data/lib/meta_project/tracker/jira/jira_tracker.rb +68 -0
- data/lib/meta_project/tracker/jira.rb +1 -0
- data/lib/meta_project/tracker/trac/trac_tracker.rb +29 -0
- data/lib/meta_project/tracker/trac.rb +1 -0
- data/lib/meta_project/tracker/xforge/ruby_forge_tracker.rb +17 -0
- data/lib/meta_project/tracker/xforge/source_forge_tracker.rb +17 -0
- data/lib/meta_project/tracker/xforge/xforge_tracker.rb +83 -0
- data/lib/meta_project/tracker/xforge.rb +3 -0
- data/lib/meta_project/tracker.rb +6 -0
- data/lib/meta_project/version_parser.rb +48 -0
- data/lib/meta_project.rb +6 -0
- data/lib/rake/contrib/xforge/base.rb +42 -0
- data/lib/rake/contrib/xforge/news_publisher.rb +34 -0
- data/lib/rake/contrib/xforge/release.rb +78 -0
- data/lib/rake/contrib/xforge.rb +3 -0
- metadata +85 -0
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
module MetaProject
|
5
|
+
module Project
|
6
|
+
module XForge
|
7
|
+
|
8
|
+
# A Session object allows authenticated interaction with a Project, such as releasing files.
|
9
|
+
#
|
10
|
+
# A Session object can be obtained via Project.login
|
11
|
+
#
|
12
|
+
class Session
|
13
|
+
|
14
|
+
# Simple enumeration of processors. Used from Session.release
|
15
|
+
class Processor
|
16
|
+
I386 = 1000
|
17
|
+
IA64 = 6000
|
18
|
+
ALPHA = 7000
|
19
|
+
ANY = 8000
|
20
|
+
PPC = 2000
|
21
|
+
MIPS = 3000
|
22
|
+
SPARC = 4000
|
23
|
+
ULTRA_SPARC = 5000
|
24
|
+
OTHER_PLATFORM = 9999
|
25
|
+
end
|
26
|
+
|
27
|
+
BOUNDARY = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"
|
28
|
+
|
29
|
+
def initialize(host, project, cookie) # :nodoc:
|
30
|
+
@host = host
|
31
|
+
@project = project
|
32
|
+
@headers = { "Cookie" => cookie }
|
33
|
+
end
|
34
|
+
|
35
|
+
# The package_id of our project
|
36
|
+
def package_id
|
37
|
+
unless(@package_id)
|
38
|
+
release_uri = "http://#{@host}/frs/admin/?group_id=#{@project.group_id}"
|
39
|
+
release_data = open(release_uri, @headers) { |data| data.read }
|
40
|
+
@package_id = release_data[/[?&]package_id=(\d+)/, 1]
|
41
|
+
raise "Couldn't get package_id" unless @package_id
|
42
|
+
end
|
43
|
+
@package_id
|
44
|
+
end
|
45
|
+
|
46
|
+
# Creates a new release containing the files specified by +filenames+ (Array) and named +release_name+.
|
47
|
+
# Optional parameters are +processor+ (which should be one of the Processor constants), +release_notes+,
|
48
|
+
# +release_changes+ and +preformatted+ which will appear on the releas page of the associated project.
|
49
|
+
#
|
50
|
+
def release(release_name, filenames, release_notes="", release_changes="", preformatted=true, processor=Processor::ANY)
|
51
|
+
release_date = Time.now.strftime("%Y-%m-%d %H:%M")
|
52
|
+
release_id = nil
|
53
|
+
|
54
|
+
puts "About to release '#{release_name}'"
|
55
|
+
puts "Files:"
|
56
|
+
puts " " + filenames.join("\n ")
|
57
|
+
puts "\nRelease Notes:\n"
|
58
|
+
puts release_notes
|
59
|
+
puts "\nRelease Changes:\n"
|
60
|
+
puts release_changes
|
61
|
+
puts "\nRelease Settings:\n"
|
62
|
+
puts "Preformatted: #{preformatted}"
|
63
|
+
puts "Processor: #{processor}"
|
64
|
+
puts "\nStarting release..."
|
65
|
+
|
66
|
+
xfiles = filenames.collect{|filename| XFile.new(filename)}
|
67
|
+
xfiles.each_with_index do |xfile, i|
|
68
|
+
first_file = i==0
|
69
|
+
puts "Releasing #{xfile.basename}..."
|
70
|
+
|
71
|
+
release_response = Net::HTTP.start(@host, 80) do |http|
|
72
|
+
query_hash = if first_file then
|
73
|
+
{
|
74
|
+
"group_id" => @project.group_id,
|
75
|
+
"package_id" => package_id,
|
76
|
+
"type_id" => xfile.bin_type_id,
|
77
|
+
"processor_id" => processor,
|
78
|
+
|
79
|
+
"release_name" => release_name,
|
80
|
+
"release_date" => release_date,
|
81
|
+
"release_notes" => release_notes,
|
82
|
+
"release_changes" => release_changes,
|
83
|
+
"preformatted" => preformatted ? "1" : "0",
|
84
|
+
"submit" => "1"
|
85
|
+
}
|
86
|
+
else
|
87
|
+
{
|
88
|
+
"group_id" => @project.group_id,
|
89
|
+
"package_id" => package_id,
|
90
|
+
"type_id" => xfile.bin_type_id,
|
91
|
+
"processor_id" => processor,
|
92
|
+
|
93
|
+
"step2" => "1",
|
94
|
+
"release_id" => release_id,
|
95
|
+
"submit" => "Add This File"
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
query = query(query_hash)
|
100
|
+
|
101
|
+
data = [
|
102
|
+
"--" + BOUNDARY,
|
103
|
+
"Content-Disposition: form-data; name=\"userfile\"; filename=\"#{xfile.basename}\"",
|
104
|
+
"Content-Type: application/octet-stream",
|
105
|
+
"Content-Transfer-Encoding: binary",
|
106
|
+
"", xfile.data, ""
|
107
|
+
].join("\x0D\x0A")
|
108
|
+
|
109
|
+
headers = @headers.merge(
|
110
|
+
"Content-Type" => "multipart/form-data; boundary=#{BOUNDARY}"
|
111
|
+
)
|
112
|
+
|
113
|
+
target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"
|
114
|
+
http.post(target + query, data, headers)
|
115
|
+
end
|
116
|
+
|
117
|
+
if first_file then
|
118
|
+
release_id = release_response.body[/release_id=(\d+)/, 1]
|
119
|
+
raise("Couldn't get release id") unless release_id
|
120
|
+
end
|
121
|
+
end
|
122
|
+
puts "Done!"
|
123
|
+
end
|
124
|
+
|
125
|
+
def publish_news(subject, details)
|
126
|
+
puts "About to publish news"
|
127
|
+
puts "Subject: '#{subject}'"
|
128
|
+
puts "Details:"
|
129
|
+
puts details
|
130
|
+
puts ""
|
131
|
+
|
132
|
+
release_response = Net::HTTP.start(@host, 80) do |http|
|
133
|
+
query_hash = {
|
134
|
+
"group_id" => @project.group_id,
|
135
|
+
"package_id" => package_id,
|
136
|
+
"post_changes" => "y",
|
137
|
+
"summary" => subject,
|
138
|
+
"details" => details
|
139
|
+
}
|
140
|
+
|
141
|
+
target = "/news/submit.php"
|
142
|
+
headers = @headers.merge(
|
143
|
+
"Content-Type" => "multipart/form-data"
|
144
|
+
)
|
145
|
+
http.post(target + query(query_hash), "", headers)
|
146
|
+
|
147
|
+
end
|
148
|
+
puts "Done!"
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def query(query_hash)
|
154
|
+
"?" + query_hash.map do |(name, value)|
|
155
|
+
[name, URI.encode(value.to_s)].join("=")
|
156
|
+
end.join("&")
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'meta_project/tracker/xforge'
|
2
|
+
|
3
|
+
module MetaProject
|
4
|
+
module Project
|
5
|
+
module XForge
|
6
|
+
class SourceForge < XForgeBase
|
7
|
+
|
8
|
+
def initialize(unix_name, cvs_mod=nil)
|
9
|
+
super("sourceforge.net", unix_name, cvs_mod)
|
10
|
+
end
|
11
|
+
|
12
|
+
def tracker_class
|
13
|
+
::MetaProject::Tracker::XForge::SourceForgeTracker
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def create_cvs(unix_name, mod)
|
19
|
+
RSCM::Cvs.new(":pserver:anonymous@cvs.sourceforge.net:/cvsroot/#{unix_name}", mod)
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_view_cvs(unix_name, mod)
|
23
|
+
view_cvs = "http://cvs.sourceforge.net/viewcvs.py/"
|
24
|
+
unix_name_mod = "#{unix_name}/#{mod}"
|
25
|
+
project_path = "#{unix_name_mod}/\#{path}"
|
26
|
+
rev = "rev=\#{revision}"
|
27
|
+
|
28
|
+
overview = "#{view_cvs}#{unix_name_mod}/"
|
29
|
+
history = "#{view_cvs}#{project_path}"
|
30
|
+
raw = "#{view_cvs}*checkout*/#{project_path}?#{rev}"
|
31
|
+
html = "#{history}?#{rev}&view=markup"
|
32
|
+
diff = "#{history}?r1=\#{previous_revision}&r2=\#{revision}"
|
33
|
+
|
34
|
+
ScmWeb.new(overview, history, raw, html, diff)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Regexp used to find projects' home page
|
38
|
+
def home_page_regexp
|
39
|
+
# This seems a little volatile
|
40
|
+
/<A href=\"(\w*:\/\/[^\"]*)\"> Project Home Page<\/A>/
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module MetaProject
|
2
|
+
module Project
|
3
|
+
module XForge
|
4
|
+
|
5
|
+
class XFile # :nodoc:
|
6
|
+
|
7
|
+
# extension => [mime_type, rubyforge_bin_type_id, rubyforge_src_type_id]
|
8
|
+
FILE_TYPES = {
|
9
|
+
".deb" => ["application/octet-stream", 1000],
|
10
|
+
|
11
|
+
# all of these can be source or binary
|
12
|
+
".rpm" => ["application/octet-stream", 2000, 5100],
|
13
|
+
".zip" => ["application/octet-stream", 3000, 5000],
|
14
|
+
".bz2" => ["application/octet-stream", 3100, 5010],
|
15
|
+
".gz" => ["application/octet-stream", 3110, 5020],
|
16
|
+
".jpg" => ["application/octet-stream", 8000],
|
17
|
+
".jpeg" => ["application/octet-stream", 8000],
|
18
|
+
".txt" => ["text/plain", 8100, 8100],
|
19
|
+
".html" => ["text/html", 8200, 8200],
|
20
|
+
".pdf" => ["application/octet-stream", 8300],
|
21
|
+
".ebuild" => ["application/octet-stream", 1300],
|
22
|
+
".exe" => ["application/octet-stream", 1100],
|
23
|
+
".dmg" => ["application/octet-stream", 1200],
|
24
|
+
".gem" => ["application/octet-stream", 1400],
|
25
|
+
".sig" => ["application/octet-stream", 8150]
|
26
|
+
}
|
27
|
+
FILE_TYPES.default = ["application/octet-stream", 9999, 5900] # default to "other", "other source"
|
28
|
+
|
29
|
+
attr_reader :basename, :ext, :content_type, :bin_type_id, :src_type_id
|
30
|
+
|
31
|
+
def initialize(filename)
|
32
|
+
@filename = filename
|
33
|
+
@basename = File.basename(filename)
|
34
|
+
@ext = File.extname(filename)
|
35
|
+
@content_type = FILE_TYPES[@ext][0]
|
36
|
+
@bin_type_id = FILE_TYPES[@ext][1]
|
37
|
+
end
|
38
|
+
|
39
|
+
def data
|
40
|
+
File.open(@filename, "rb") { |file| file.read }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
module MetaProject
|
6
|
+
module Project
|
7
|
+
module XForge
|
8
|
+
class XForgeBase < Base
|
9
|
+
|
10
|
+
def initialize(host, unix_name, cvs_mod)
|
11
|
+
@host = host
|
12
|
+
@unix_name = unix_name
|
13
|
+
|
14
|
+
@tracker = tracker_class.new(group_id_uri("tracker"), self)
|
15
|
+
|
16
|
+
unless(cvs_mod.nil?)
|
17
|
+
@scm = create_cvs(unix_name, cvs_mod)
|
18
|
+
@scm_web = create_view_cvs(unix_name, cvs_mod)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_yaml_properties
|
23
|
+
["@host", "@unix_name"]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Logs in and returns a Session
|
27
|
+
def login(user_name, password)
|
28
|
+
http = Net::HTTP.new(@host, 80)
|
29
|
+
|
30
|
+
login_response = http.start do |http|
|
31
|
+
data = [
|
32
|
+
"login=1",
|
33
|
+
"form_loginname=#{user_name}",
|
34
|
+
"form_pw=#{password}"
|
35
|
+
].join("&")
|
36
|
+
http.post("/account/login.php", data)
|
37
|
+
end
|
38
|
+
|
39
|
+
cookie = login_response["set-cookie"]
|
40
|
+
raise "Login failed" unless cookie
|
41
|
+
Session.new(@host, self, cookie)
|
42
|
+
end
|
43
|
+
|
44
|
+
# The group_id of this project
|
45
|
+
def group_id
|
46
|
+
unless(@group_id)
|
47
|
+
regexp = /stats\/[?&]group_id=(\d+)/
|
48
|
+
html = open(project_uri) { |data| data.read }
|
49
|
+
@group_id = html[regexp, 1]
|
50
|
+
raise "Couldn't get group_id" unless @group_id
|
51
|
+
end
|
52
|
+
@group_id
|
53
|
+
end
|
54
|
+
|
55
|
+
def project_uri
|
56
|
+
"http://#{@host}/projects/#{@unix_name}/"
|
57
|
+
end
|
58
|
+
|
59
|
+
def group_id_uri(path, postfix="")
|
60
|
+
"http://#{@host}/#{path}/?group_id=#{group_id}#{postfix}"
|
61
|
+
end
|
62
|
+
|
63
|
+
# The home page of this project
|
64
|
+
def home_page
|
65
|
+
unless(@home_page)
|
66
|
+
html = open(project_uri) { |data| data.read }
|
67
|
+
@home_page = html[home_page_regexp, 1]
|
68
|
+
raise "Couldn't get home_page" unless @home_page
|
69
|
+
end
|
70
|
+
@home_page
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module MetaProject
|
2
|
+
module ProjectAnalyzer
|
3
|
+
# Creates a project from an scm web url. The project has a +tracker+, +scm+ and +scm_web+.
|
4
|
+
def project_from_scm_web(url, options=nil)
|
5
|
+
# RubyForge
|
6
|
+
if(url =~ /http:\/\/rubyforge.org\/cgi-bin\/viewcvs.cgi\/(.*)[\/]?\?cvsroot=(.*)/)
|
7
|
+
unix_name = $2
|
8
|
+
mod = $1[-1..-1] == "/" ? $1[0..-2] : $1
|
9
|
+
return Project::XForge::RubyForge.new(unix_name, mod)
|
10
|
+
end
|
11
|
+
|
12
|
+
# SourceForge
|
13
|
+
if(url =~ /http:\/\/cvs.sourceforge.net\/viewcvs.py\/([^\/]*)\/(.*)/)
|
14
|
+
unix_name = $1
|
15
|
+
mod = $2[-1..-1] == "/" ? $2[0..-2] : $2
|
16
|
+
return Project::XForge::SourceForge.new(unix_name, mod)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Trac
|
20
|
+
if(url =~ /(http:\/\/.*)\/browser\/(.*)/)
|
21
|
+
trac_base_url = $1
|
22
|
+
svn_path = $2[-1..-1] == "/" ? $2[0..-2] : $2
|
23
|
+
return Project::Trac::TracProject.new(trac_base_url, options[:svn_root_url], svn_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Codehaus SVN
|
27
|
+
if(url =~ /http:\/\/svn.(.*).codehaus.org\/(.*)/)
|
28
|
+
svn_id = $1
|
29
|
+
svn_path = $2[-1..-1] == "/" ? $2[0..-2] : $2
|
30
|
+
return Project::Codehaus::CodehausProjectSvn.new(svn_id, svn_path, options[:jira_id])
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module MetaProject
|
2
|
+
|
3
|
+
# An ScmWeb instance is capable of generating URLs to various files and diffs
|
4
|
+
# in an online scm web interface.
|
5
|
+
class ScmWeb
|
6
|
+
|
7
|
+
# The variables to use in +uri_specs+ are:
|
8
|
+
#
|
9
|
+
# * path
|
10
|
+
# * revision
|
11
|
+
# * previous_revision
|
12
|
+
#
|
13
|
+
def initialize(overview_spec, history_spec, raw_spec, html_spec, diff_spec)
|
14
|
+
@overview_spec, @history_spec, @raw_spec, @html_spec, @diff_spec = overview_spec, history_spec, raw_spec, html_spec, diff_spec
|
15
|
+
end
|
16
|
+
|
17
|
+
def overview
|
18
|
+
file_uri(nil, nil, @overview_spec)
|
19
|
+
end
|
20
|
+
|
21
|
+
def history(path)
|
22
|
+
file_uri(path, nil, @history_spec)
|
23
|
+
end
|
24
|
+
|
25
|
+
def raw(path, revision)
|
26
|
+
file_uri(path, revision, @raw_spec)
|
27
|
+
end
|
28
|
+
|
29
|
+
def html(path, revision)
|
30
|
+
file_uri(path, revision, @html_spec)
|
31
|
+
end
|
32
|
+
|
33
|
+
def diff(path, revision, previous_revision)
|
34
|
+
file_uri(path, revision, @diff_spec, previous_revision)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Returns the file URI for +path+. Valid options are:
|
40
|
+
#
|
41
|
+
# * :type => ["overview"|"html"|"diff"|"raw"]
|
42
|
+
# * :revision
|
43
|
+
# * :previous_revision
|
44
|
+
def file_uri(path="", revision=nil, spec=@overview_spec, previous_revision=nil)
|
45
|
+
begin
|
46
|
+
eval("\"#{spec}\"", binding)
|
47
|
+
rescue NameError
|
48
|
+
raise "Couldn't evaluate '#{spec}'"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MetaProject
|
2
|
+
module Tracker
|
3
|
+
|
4
|
+
# Tracker objects are responsible for interacting with issue trackers (bug trackers).
|
5
|
+
# They know how to recognise issue identifiers in strings (typically from SCM commit
|
6
|
+
# messages) and turn these into HTML links that point to the associated issue on an
|
7
|
+
# issue tracker installation running somewhere else.
|
8
|
+
class Base
|
9
|
+
def self.classes
|
10
|
+
[
|
11
|
+
::Tracker::Jira::JiraProject,
|
12
|
+
::Tracker::XForge::RubyForgeProject,
|
13
|
+
::Tracker::Trac::TracProject
|
14
|
+
]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module MetaProject
|
2
|
+
module Tracker
|
3
|
+
# This module should be included by trackers that follow a digit-based issue scheme
|
4
|
+
module DigitIssues
|
5
|
+
def identifier_regexp
|
6
|
+
/#(\d+)/
|
7
|
+
end
|
8
|
+
|
9
|
+
def identifier_examples
|
10
|
+
["#1926", "#1446"]
|
11
|
+
end
|
12
|
+
|
13
|
+
# TODO: find a way to extract just the issue summaries so they can be stored in dc as an array
|
14
|
+
# embedded in the revision object. that way we don't alter the original commit message
|
15
|
+
def markup(text)
|
16
|
+
text.gsub(identifier_regexp) do |match|
|
17
|
+
issue_identifier = $1
|
18
|
+
issue = issue(issue_identifier)
|
19
|
+
issue ? "<a href=\"#{issue.uri}\">#{issue.summary}</a>" : "\##{issue_identifier}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'xmlrpc/client'
|
2
|
+
|
3
|
+
module MetaProject
|
4
|
+
module Tracker
|
5
|
+
module Jira
|
6
|
+
class JiraTracker
|
7
|
+
JIRA_API = "jira1"
|
8
|
+
|
9
|
+
def initialize(rooturl=nil, identifier=nil, username=nil, password=nil)
|
10
|
+
@rooturl, @identifier, @username, @password = rooturl, identifier, username, password
|
11
|
+
end
|
12
|
+
|
13
|
+
def identifier_regexp
|
14
|
+
/([A-Z]+-[\d]+)/
|
15
|
+
end
|
16
|
+
|
17
|
+
def identifier_examples
|
18
|
+
["DC-420", "PICO-12"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def overview
|
22
|
+
"#{@rooturl}/browse/#{@identifier}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def issue(issue_identifier)
|
26
|
+
session = login
|
27
|
+
begin
|
28
|
+
issue = session.getIssue(issue_identifier)
|
29
|
+
Issue.new("#{@rooturl}/browse/#{issue_identifier}", issue["summary"])
|
30
|
+
rescue XMLRPC::FaultException
|
31
|
+
# Probably bad issue number
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def markup(text)
|
37
|
+
text.gsub(identifier_regexp) do |match|
|
38
|
+
issue_identifier = $1
|
39
|
+
issue = issue(issue_identifier)
|
40
|
+
issue ? "<a href=\"#{issue.uri}\">#{issue_identifier}: #{issue.summary}</a>" : issue_identifier
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def login
|
47
|
+
client = XMLRPC::Client.new2("#{@rooturl}/rpc/xmlrpc")
|
48
|
+
token = client.call("#{JIRA_API}.login", @username, @password)
|
49
|
+
Session.new(client, token)
|
50
|
+
end
|
51
|
+
|
52
|
+
# This wrapper around XMLRPC::Client that allows simpler method calls
|
53
|
+
# via method_missing and doesn't require to manage the token
|
54
|
+
class Session
|
55
|
+
def initialize(client, token)
|
56
|
+
@client, @token = client, token
|
57
|
+
end
|
58
|
+
|
59
|
+
def method_missing(sym, args, &block)
|
60
|
+
token_args = [@token] << args
|
61
|
+
xmlrpc_method = "#{JIRA_API}.#{sym.to_s}"
|
62
|
+
@client.call(xmlrpc_method, *token_args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'meta_project/tracker/jira/jira_tracker'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module MetaProject
|
2
|
+
module Tracker
|
3
|
+
module Trac
|
4
|
+
class TracTracker < ::MetaProject::Tracker::Base
|
5
|
+
include ::MetaProject::Tracker::DigitIssues
|
6
|
+
|
7
|
+
def initialize(trac_base_url)
|
8
|
+
@trac_base_url = trac_base_url
|
9
|
+
end
|
10
|
+
|
11
|
+
def overview
|
12
|
+
"#{@trac_base_url}/report"
|
13
|
+
end
|
14
|
+
|
15
|
+
def issue(issue_identifier)
|
16
|
+
issue_uri = "#{@trac_base_url}/ticket/#{issue_identifier}"
|
17
|
+
begin
|
18
|
+
html = open(issue_uri) { |data| data.read }
|
19
|
+
summary = html[/Ticket ##{issue_identifier}\s*<\/h1>\s*<h2>([^<]*)<\/h2>/n, 1]
|
20
|
+
::MetaProject::Tracker::Issue.new(issue_uri, summary)
|
21
|
+
rescue OpenURI::HTTPError
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'meta_project/tracker/trac/trac_tracker'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MetaProject
|
2
|
+
module Tracker
|
3
|
+
module XForge
|
4
|
+
class RubyForgeTracker < XForgeTracker
|
5
|
+
|
6
|
+
def subtracker_regexp
|
7
|
+
/\/tracker\/\?atid=(\d+)&group_id=\d*&func=browse/
|
8
|
+
end
|
9
|
+
|
10
|
+
def issue_regexp(identifier)
|
11
|
+
/<a href=\"\/tracker\/index.php\?func=detail&aid=#{identifier}&group_id=\d+&atid=\d+\">([^<]*)<\/a>/
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module MetaProject
|
2
|
+
module Tracker
|
3
|
+
module XForge
|
4
|
+
class SourceForgeTracker < XForgeTracker
|
5
|
+
|
6
|
+
def subtracker_regexp
|
7
|
+
/\/tracker\/\?atid=(\d+)&group_id=\d*&func=browse/
|
8
|
+
end
|
9
|
+
|
10
|
+
def issue_regexp(identifier)
|
11
|
+
/<a href=\"\/tracker\/index.php\?func=detail&aid=#{identifier}&group_id=\d+&atid=\d+\">([^<]*)<\/a>/
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|