xforge 0.3.5 → 0.4.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.
Files changed (59) hide show
  1. data/CHANGES +34 -0
  2. data/Rakefile +5 -5
  3. data/lib/meta_project.rb +6 -0
  4. data/lib/meta_project/project.rb +4 -0
  5. data/lib/meta_project/project/base.rb +7 -0
  6. data/lib/meta_project/project/codehaus.rb +1 -0
  7. data/lib/meta_project/project/codehaus/codehaus_project_svn.rb +26 -0
  8. data/lib/meta_project/project/trac.rb +1 -0
  9. data/lib/meta_project/project/trac/trac_project.rb +26 -0
  10. data/lib/meta_project/project/xforge.rb +5 -0
  11. data/lib/meta_project/project/xforge/ruby_forge.rb +46 -0
  12. data/lib/meta_project/project/xforge/session.rb +162 -0
  13. data/lib/meta_project/project/xforge/source_forge.rb +46 -0
  14. data/lib/meta_project/project/xforge/xfile.rb +45 -0
  15. data/lib/meta_project/project/xforge/xforge_base.rb +76 -0
  16. data/lib/meta_project/project_analyzer.rb +36 -0
  17. data/lib/meta_project/scm_web.rb +53 -0
  18. data/lib/meta_project/tracker.rb +6 -0
  19. data/lib/meta_project/tracker/base.rb +18 -0
  20. data/lib/meta_project/tracker/digit_issues.rb +24 -0
  21. data/lib/meta_project/tracker/issue.rb +11 -0
  22. data/lib/meta_project/tracker/jira.rb +1 -0
  23. data/lib/meta_project/tracker/jira/jira_tracker.rb +68 -0
  24. data/lib/meta_project/tracker/trac.rb +1 -0
  25. data/lib/meta_project/tracker/trac/trac_tracker.rb +29 -0
  26. data/lib/meta_project/tracker/xforge.rb +3 -0
  27. data/lib/meta_project/tracker/xforge/ruby_forge_tracker.rb +17 -0
  28. data/lib/meta_project/tracker/xforge/source_forge_tracker.rb +17 -0
  29. data/lib/meta_project/tracker/xforge/xforge_tracker.rb +83 -0
  30. data/lib/{xforge → meta_project}/version_parser.rb +6 -6
  31. data/lib/rake/contrib/xforge/base.rb +2 -3
  32. data/lib/rake/contrib/xforge/news_publisher.rb +1 -5
  33. data/lib/rake/contrib/xforge/release.rb +3 -7
  34. data/lib/xforge.rb +0 -1
  35. metadata +30 -27
  36. data/lib/scm_web/base.rb +0 -12
  37. data/lib/scm_web/file_uri.rb +0 -21
  38. data/lib/scm_web/view_cvs.rb +0 -44
  39. data/lib/tracker/base.rb +0 -16
  40. data/lib/tracker/bugzilla/project.rb +0 -8
  41. data/lib/tracker/digit_issues.rb +0 -22
  42. data/lib/tracker/fog_bugz/project.rb +0 -8
  43. data/lib/tracker/issue.rb +0 -9
  44. data/lib/tracker/jira.rb +0 -2
  45. data/lib/tracker/jira/host.rb +0 -40
  46. data/lib/tracker/jira/project.rb +0 -43
  47. data/lib/tracker/mantis/project.rb +0 -8
  48. data/lib/tracker/scarab/project.rb +0 -8
  49. data/lib/tracker/trac.rb +0 -1
  50. data/lib/tracker/trac/project.rb +0 -35
  51. data/lib/tracker/xforge.rb +0 -2
  52. data/lib/tracker/xforge/base.rb +0 -77
  53. data/lib/tracker/xforge/rubyforge.rb +0 -7
  54. data/lib/xforge/host.rb +0 -26
  55. data/lib/xforge/project.rb +0 -87
  56. data/lib/xforge/rubyforge.rb +0 -50
  57. data/lib/xforge/session.rb +0 -158
  58. data/lib/xforge/sourceforge.rb +0 -46
  59. 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,6 @@
1
+ require 'meta_project/tracker/base'
2
+ require 'meta_project/tracker/digit_issues'
3
+ require 'meta_project/tracker/issue'
4
+ require 'meta_project/tracker/trac'
5
+ require 'meta_project/tracker/xforge'
6
+ require 'meta_project/tracker/jira'
@@ -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,11 @@
1
+ module MetaProject
2
+ module Tracker
3
+ class Issue
4
+ attr_reader :uri, :summary
5
+
6
+ def initialize(uri, summary)
7
+ @uri, @summary = uri, summary
8
+ end
9
+ end
10
+ end
11
+ 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,3 @@
1
+ require 'meta_project/tracker/xforge/xforge_tracker'
2
+ require 'meta_project/tracker/xforge/ruby_forge_tracker'
3
+ require 'meta_project/tracker/xforge/source_forge_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+)&amp;group_id=\d*&amp;func=browse/
8
+ end
9
+
10
+ def issue_regexp(identifier)
11
+ /<a href=\"\/tracker\/index.php\?func=detail&amp;aid=#{identifier}&amp;group_id=\d+&amp;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