xforge 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +34 -0
- data/Rakefile +5 -5
- data/lib/meta_project.rb +6 -0
- data/lib/meta_project/project.rb +4 -0
- data/lib/meta_project/project/base.rb +7 -0
- data/lib/meta_project/project/codehaus.rb +1 -0
- data/lib/meta_project/project/codehaus/codehaus_project_svn.rb +26 -0
- data/lib/meta_project/project/trac.rb +1 -0
- data/lib/meta_project/project/trac/trac_project.rb +26 -0
- data/lib/meta_project/project/xforge.rb +5 -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_analyzer.rb +36 -0
- data/lib/meta_project/scm_web.rb +53 -0
- data/lib/meta_project/tracker.rb +6 -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.rb +1 -0
- data/lib/meta_project/tracker/jira/jira_tracker.rb +68 -0
- data/lib/meta_project/tracker/trac.rb +1 -0
- data/lib/meta_project/tracker/trac/trac_tracker.rb +29 -0
- data/lib/meta_project/tracker/xforge.rb +3 -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/{xforge → meta_project}/version_parser.rb +6 -6
- data/lib/rake/contrib/xforge/base.rb +2 -3
- data/lib/rake/contrib/xforge/news_publisher.rb +1 -5
- data/lib/rake/contrib/xforge/release.rb +3 -7
- data/lib/xforge.rb +0 -1
- metadata +30 -27
- data/lib/scm_web/base.rb +0 -12
- data/lib/scm_web/file_uri.rb +0 -21
- data/lib/scm_web/view_cvs.rb +0 -44
- data/lib/tracker/base.rb +0 -16
- data/lib/tracker/bugzilla/project.rb +0 -8
- data/lib/tracker/digit_issues.rb +0 -22
- data/lib/tracker/fog_bugz/project.rb +0 -8
- data/lib/tracker/issue.rb +0 -9
- data/lib/tracker/jira.rb +0 -2
- data/lib/tracker/jira/host.rb +0 -40
- data/lib/tracker/jira/project.rb +0 -43
- data/lib/tracker/mantis/project.rb +0 -8
- data/lib/tracker/scarab/project.rb +0 -8
- data/lib/tracker/trac.rb +0 -1
- data/lib/tracker/trac/project.rb +0 -35
- data/lib/tracker/xforge.rb +0 -2
- data/lib/tracker/xforge/base.rb +0 -77
- data/lib/tracker/xforge/rubyforge.rb +0 -7
- data/lib/xforge/host.rb +0 -26
- data/lib/xforge/project.rb +0 -87
- data/lib/xforge/rubyforge.rb +0 -50
- data/lib/xforge/session.rb +0 -158
- data/lib/xforge/sourceforge.rb +0 -46
- data/lib/xforge/xfile.rb +0 -41
@@ -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 @@
|
|
1
|
+
require 'meta_project/tracker/jira/jira_tracker'
|
@@ -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/trac/trac_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,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
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'meta_project/tracker/base'
|
2
|
+
require 'meta_project/tracker/digit_issues'
|
3
|
+
require 'meta_project/tracker/issue'
|
4
|
+
|
5
|
+
module MetaProject
|
6
|
+
module Tracker
|
7
|
+
module XForge
|
8
|
+
class XForgeTracker < Base
|
9
|
+
include ::MetaProject::Tracker::DigitIssues
|
10
|
+
|
11
|
+
attr_accessor :overview, :project
|
12
|
+
|
13
|
+
# TODO: don't pass in project!! pass in hostname and id!
|
14
|
+
def initialize(overview, project)
|
15
|
+
@overview, @project = overview, project
|
16
|
+
end
|
17
|
+
|
18
|
+
# Finds an Issue by +identifier+
|
19
|
+
def issue(identifier)
|
20
|
+
sub_trackers = atids.collect {|atid| SubTracker.new(self, atid)}
|
21
|
+
sub_trackers.each do |sub_tracker|
|
22
|
+
issue = sub_tracker.issue(identifier)
|
23
|
+
return issue unless issue.nil?
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def markup(text)
|
29
|
+
text.gsub(identifier_regexp) do |match|
|
30
|
+
issue_identifier = $1
|
31
|
+
issue = issue(issue_identifier)
|
32
|
+
issue ? "<a href=\"#{issue.uri}\">\##{issue_identifier}: #{issue.summary}</a>" : "\##{issue_identifier}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class SubTracker
|
37
|
+
attr_reader :uri
|
38
|
+
|
39
|
+
def initialize(tracker, atid)
|
40
|
+
@tracker = tracker
|
41
|
+
@atid = atid
|
42
|
+
# FIXME: This will only show open items.
|
43
|
+
@uri = "#{tracker.overview}&atid=#{atid}&func=browse"
|
44
|
+
end
|
45
|
+
|
46
|
+
def issue(identifier)
|
47
|
+
html = open(uri) { |data| data.read }
|
48
|
+
|
49
|
+
regexp = @tracker.issue_regexp(identifier)
|
50
|
+
if(html =~ regexp)
|
51
|
+
issue_uri = @tracker.project.group_id_uri("tracker/index.php", "&atid=#{@atid}&func=detail&aid=#{identifier}")
|
52
|
+
return Issue.new(issue_uri, $1)
|
53
|
+
end
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# The ids of the subtrackers
|
61
|
+
def atids
|
62
|
+
html = open(overview) { |data| data.read }
|
63
|
+
|
64
|
+
# TODO: there has to be a better way to extract the atids from the HTML!
|
65
|
+
atids = []
|
66
|
+
offset = 0
|
67
|
+
look_for_atid = true
|
68
|
+
while(look_for_atid)
|
69
|
+
match_data = subtracker_regexp.match(html[offset..-1])
|
70
|
+
if(match_data)
|
71
|
+
offset += match_data.begin(1)
|
72
|
+
atids << match_data[1]
|
73
|
+
else
|
74
|
+
look_for_atid = false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
atids
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|