xforge 0.2.1 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,5 +1,15 @@
1
1
  = XForge Changelog
2
2
 
3
+ == Version 0.3.1
4
+
5
+ This XForge release adds initial support for Trac and JIRA.
6
+
7
+ * Added support for formatting of text containing issue identifiers
8
+ * Refactored trackers into other modules
9
+ * Added support for JIRA issue tracker
10
+ * Added support for Trac's issue tracker
11
+ * Added support for diff URLs on SourceForge and RubyForge
12
+
3
13
  == Version 0.2.1
4
14
 
5
15
  This XForge release adds support for tracker meta info
data/README CHANGED
@@ -30,7 +30,11 @@ Download and install XForge with the following.
30
30
 
31
31
  == Usage
32
32
 
33
- See XForge, Rake::XForge::Release and Rake::XForge::NewsPublisher.
33
+ XForge itself is released with XForge. so check out XForge's own Rakefile (http://tinyurl.com/a23u5) and CHANGES (http://tinyurl.com/9qxxf) files for the best examples on how to use it.
34
+
35
+ XForge can parse release summary and changes from CHANGES if you format it the way XForge's own CHANGES is formatted. Also make sure your Rakefile's PKG_VERSION is in sync with the latest version specified in the CHANGES file.
36
+
37
+ If you're writing an application that interacts with XForge, check out the RDoc API.
34
38
 
35
39
  ---
36
40
 
data/Rakefile CHANGED
@@ -24,7 +24,7 @@ require 'rake/rdoctask'
24
24
  #
25
25
  # REMEMBER TO KEEP PKG_VERSION IN SYNC WITH CHANGELOG
26
26
  PKG_NAME = "xforge"
27
- PKG_VERSION = "0.2.1"
27
+ PKG_VERSION = "0.3.1"
28
28
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
29
29
  PKG_FILES = FileList[
30
30
  '[A-Z]*',
@@ -48,7 +48,7 @@ rd = Rake::RDocTask.new("rdoc") do |rdoc|
48
48
  # rdoc.template = 'doc/jamis.rb'
49
49
  rdoc.title = "XForge"
50
50
  rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README'
51
- rdoc.rdoc_files.include('README', 'MIT-LICENSE', 'TODO', 'CHANGES')
51
+ rdoc.rdoc_files.include('README', 'MIT-LICENSE', 'CHANGES')
52
52
  rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
53
53
  rdoc.rdoc_files.exclude('doc/**/*_attrs.rdoc')
54
54
  end
@@ -117,7 +117,7 @@ task :todo do
117
117
  egrep /#.*(FIXME|TODO|TBD)/
118
118
  end
119
119
 
120
- task :release => [:verify_env_vars, :release_files, :publish_doc, :publish_news]
120
+ task :release => [:verify_env_vars, :release_files, :publish_doc, :publish_news, :tag]
121
121
 
122
122
  task :verify_env_vars do
123
123
  raise "RUBYFORGE_USER environment variable not set!" unless ENV['RUBYFORGE_USER']
@@ -42,6 +42,7 @@ module ScmWeb
42
42
 
43
43
  project_unix_name = project.unix_name
44
44
  revision = options[:revision]
45
+ previous_revision = options[:previous_revision]
45
46
  eval("\"#{uri_spec}\"", binding)
46
47
  end
47
48
  end
@@ -0,0 +1,2 @@
1
+ require 'tracker/jira/host'
2
+ require 'tracker/jira/project'
@@ -0,0 +1,40 @@
1
+ require 'xmlrpc/client'
2
+
3
+ module Tracker
4
+ module Jira
5
+ class Host
6
+ JIRA_API = "jira1"
7
+
8
+ attr_reader :uri
9
+
10
+ def initialize(uri, username, password)
11
+ @uri, @username, @password = uri, username, password
12
+ end
13
+
14
+ def project(identifier)
15
+ Project.new(self, identifier)
16
+ end
17
+
18
+ def login
19
+ client = XMLRPC::Client.new2("#{uri}/rpc/xmlrpc")
20
+ token = client.call("#{JIRA_API}.login", @username, @password)
21
+ Session.new(client, token)
22
+ end
23
+
24
+ end
25
+
26
+ # This wrapper around XMLRPC::Client that allows simpler method calls
27
+ # via method_missing and doesn't require to manage the token
28
+ class Session
29
+ def initialize(client, token)
30
+ @client, @token = client, token
31
+ end
32
+
33
+ def method_missing(sym, args, &block)
34
+ token_args = [@token] << args
35
+ xmlrpc_method = "#{Host::JIRA_API}.#{sym.to_s}"
36
+ @client.call(xmlrpc_method, *token_args)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ module Tracker
2
+ module Jira
3
+ class Project
4
+ def initialize(host, identifier)
5
+ @host, @identifier = host, identifier
6
+ end
7
+
8
+ def identifier_regexp
9
+ /([A-Z]+-[\d]+)/
10
+ end
11
+
12
+ def identifier_examples
13
+ ["DC-420", "PICO-12"]
14
+ end
15
+
16
+ def uri
17
+ "#{@host.uri}/browse/#{@identifier}"
18
+ end
19
+
20
+ def issue(issue_identifier)
21
+ session = @host.login
22
+ begin
23
+ issue = session.getIssue(issue_identifier)
24
+ Issue.new("#{@host.uri}/browse/#{issue_identifier}", issue["summary"])
25
+ rescue XMLRPC::FaultException
26
+ # Probably bad issue number
27
+ nil
28
+ end
29
+ end
30
+
31
+ def markup(text)
32
+ text.gsub(identifier_regexp) do |match|
33
+ issue_identifier = $1
34
+ issue = issue(issue_identifier)
35
+ issue ? "<a href=\"#{issue.uri}\">#{issue.summary}</a>" : issue_identifier
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1 @@
1
+ require 'tracker/trac/project'
@@ -0,0 +1,37 @@
1
+ module Tracker
2
+ module Trac
3
+ class Project
4
+ def initialize(uri)
5
+ @uri = uri
6
+ end
7
+
8
+ def identifier_regexp
9
+ /#(\d+)/
10
+ end
11
+
12
+ def identifier_examples
13
+ ["#1926", "#1446"]
14
+ end
15
+
16
+ def issue(issue_identifier)
17
+ issue_uri = "#{@uri}/ticket/#{issue_identifier}"
18
+ begin
19
+ html = open(issue_uri) { |data| data.read }
20
+ summary = html[/Ticket ##{issue_identifier}\s*<\/h1>\s*<h2>([^<]*)<\/h2>/n, 1]
21
+ Issue.new(issue_uri, summary)
22
+ rescue OpenURI::HTTPError
23
+ nil
24
+ end
25
+ end
26
+
27
+ def markup(text)
28
+ text.gsub(identifier_regexp) do |match|
29
+ issue_identifier = $1
30
+ issue = issue(issue_identifier)
31
+ issue ? "<a href=\"#{issue.uri}\">#{issue.summary}</a>" : "\##{issue_identifier}"
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,2 @@
1
+ require 'tracker/xforge/base'
2
+ require 'tracker/xforge/rubyforge'
@@ -0,0 +1,84 @@
1
+ module Tracker
2
+ module XForge
3
+ # TODO: rename to Project
4
+ class Base
5
+ attr_reader :uri, :project
6
+
7
+ def identifier_regexp
8
+ /#(\d+)/
9
+ end
10
+
11
+ # Examples of what will be recognised as issue identifiers in #markup
12
+ def identifier_examples
13
+ ["#1462", "#872"]
14
+ end
15
+
16
+ def initialize(uri, project)
17
+ @uri, @project = uri, project
18
+ end
19
+
20
+ # Finds an Issue by +identifier+
21
+ def issue(identifier)
22
+ sub_trackers = atids.collect {|atid| SubTracker.new(self, atid)}
23
+ sub_trackers.each do |sub_tracker|
24
+ issue = sub_tracker.issue(identifier)
25
+ return issue unless issue.nil?
26
+ end
27
+ nil
28
+ end
29
+
30
+ def markup(text)
31
+ text.gsub(identifier_regexp) do |match|
32
+ issue_identifier = $1
33
+ issue = issue(issue_identifier)
34
+ issue ? "<a href=\"#{issue.uri}\">#{issue.summary}</a>" : "\##{issue_identifier}"
35
+ end
36
+ end
37
+
38
+ class SubTracker
39
+ attr_reader :uri
40
+
41
+ def initialize(rubyforge, atid)
42
+ @rubyforge = rubyforge
43
+ @atid = atid
44
+ # FIXME: This will only show open items.
45
+ @uri = "#{rubyforge.uri}&atid=#{atid}&func=browse"
46
+ end
47
+
48
+ def issue(identifier)
49
+ html = open(uri) { |data| data.read }
50
+
51
+ regexp = /<a href=\"\/tracker\/index.php\?func=detail&aid=#{identifier}&group_id=\d+&atid=\d+\">(.*)<\/a>/
52
+ if(html =~ regexp)
53
+ issue_uri = @rubyforge.project.group_id_uri("tracker/index.php", "&atid=#{@atid}&func=detail&aid=#{identifier}")
54
+ return Issue.new(issue_uri, $1)
55
+ end
56
+ nil
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ # The ids of the subtrackers
63
+ def atids
64
+ html = open(uri) { |data| data.read }
65
+
66
+ # TODO: there has to be a better way to extract the atids from the HTML!
67
+ atids = []
68
+ offset = 0
69
+ look_for_atid = true
70
+ while(look_for_atid)
71
+ match_data = /\/tracker\/\?atid=(\d+)&group_id=\d*&func=browse/.match(html[offset..-1])
72
+ if(match_data)
73
+ offset += match_data.begin(1)
74
+ atids << match_data[1]
75
+ else
76
+ look_for_atid = false
77
+ end
78
+ end
79
+ atids
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,6 @@
1
+ module Tracker
2
+ module XForge
3
+ class RubyForge < Base
4
+ end
5
+ end
6
+ end
data/lib/xforge.rb CHANGED
@@ -6,6 +6,8 @@ require 'xforge/project'
6
6
  require 'xforge/session'
7
7
  require 'xforge/xfile'
8
8
  require 'scm_web/view_cvs'
9
- require 'tracker/rubyforge'
10
9
  require 'tracker/issue'
10
+ require 'tracker/xforge'
11
+ require 'tracker/jira'
12
+ require 'tracker/trac'
11
13
  require 'rake/contrib/xforge'
@@ -76,7 +76,7 @@ module XForge
76
76
  end
77
77
 
78
78
  def tracker
79
- @tracker ||= Tracker::RubyForge.new(group_id_uri("tracker"), self)
79
+ @tracker ||= @host.tracker(self)
80
80
  end
81
81
  end
82
82
 
@@ -1,12 +1,14 @@
1
1
  module XForge
2
2
  class RubyForge < Host
3
3
  VIEW_CVS = "http://rubyforge.org/cgi-bin/viewcvs.cgi/"
4
- PATH_CVSROOT = "\#{path}?cvsroot=\#{project_unix_name}"
4
+ CVSROOT = "?cvsroot=\#{project_unix_name}"
5
+ PATH_CVSROOT = "\#{path}#{CVSROOT}"
5
6
  PATH_CVSROOT_REV = "#{PATH_CVSROOT}&rev=\#{revision}"
6
7
 
7
8
  OVERVIEW = "#{VIEW_CVS}#{PATH_CVSROOT}"
8
- RAW = "#{VIEW_CVS}*checkout*/#{PATH_CVSROOT_REV}"
9
- HTML = "#{VIEW_CVS}#{PATH_CVSROOT_REV}&content-type=text/vnd.viewcvs-markup"
9
+ RAW = "#{VIEW_CVS}*checkout*/#{PATH_CVSROOT_REV}"
10
+ HTML = "#{VIEW_CVS}#{PATH_CVSROOT_REV}&content-type=text/vnd.viewcvs-markup"
11
+ DIFF = "#{VIEW_CVS}\#{path}.diff#{CVSROOT}&r1=\#{previous_revision}&r2=\#{revision}"
10
12
 
11
13
  def initialize
12
14
  super('rubyforge.org')
@@ -26,7 +28,7 @@ module XForge
26
28
 
27
29
  def scm_web(project)
28
30
  module_regexp = /href=\"(\w+)\/\?cvsroot=#{project.unix_name}/
29
- ::ScmWeb::ViewCvs.new({:overview => OVERVIEW, :raw => RAW, :html => HTML}, project, module_regexp)
31
+ ::ScmWeb::ViewCvs.new({:overview => OVERVIEW, :raw => RAW, :html => HTML, :diff => DIFF}, project, module_regexp)
30
32
  end
31
33
 
32
34
  # Regexp used to find projects' home page
@@ -35,5 +37,8 @@ module XForge
35
37
  /<a href=\"(\w*:\/\/[^\"]*)\"><img src=\"\/themes\/osx\/images\/ic\/home/
36
38
  end
37
39
 
40
+ def tracker(project)
41
+ Tracker::XForge::RubyForge.new(project.group_id_uri("tracker"), project)
42
+ end
38
43
  end
39
44
  end
@@ -5,8 +5,9 @@ module XForge
5
5
  REV = "rev=\#{revision}"
6
6
 
7
7
  OVERVIEW = "#{VIEW_CVS}#{PROJECT_PATH}"
8
- RAW = "#{VIEW_CVS}*checkout*/#{PROJECT_PATH}?#{REV}"
9
- HTML = "#{OVERVIEW}?#{REV}&view=markup"
8
+ RAW = "#{VIEW_CVS}*checkout*/#{PROJECT_PATH}?#{REV}"
9
+ HTML = "#{OVERVIEW}?#{REV}&view=markup"
10
+ DIFF = "#{OVERVIEW}?r1=\#{previous_revision}&r2=\#{revision}"
10
11
 
11
12
  def initialize
12
13
  super("sourceforge.net")
@@ -26,7 +27,7 @@ module XForge
26
27
 
27
28
  def scm_web(project)
28
29
  module_regexp = /viewcvs\.py\/#{project.unix_name}\/(\w+)\//
29
- ::ScmWeb::ViewCvs.new({:overview => OVERVIEW, :raw => RAW, :html => HTML}, project, module_regexp)
30
+ ::ScmWeb::ViewCvs.new({:overview => OVERVIEW, :raw => RAW, :html => HTML, :diff => DIFF}, project, module_regexp)
30
31
  end
31
32
 
32
33
  # Regexp used to find projects' home page
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: xforge
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.2.1
7
- date: 2005-08-14 00:00:00 -04:00
6
+ version: 0.3.1
7
+ date: 2005-08-15 00:00:00 -04:00
8
8
  summary: Ruby based make-like utility.
9
9
  require_paths:
10
10
  - lib
@@ -42,7 +42,14 @@ files:
42
42
  - lib/rake/contrib/xforge/release.rb
43
43
  - lib/scm_web/view_cvs.rb
44
44
  - lib/tracker/issue.rb
45
- - lib/tracker/rubyforge.rb
45
+ - lib/tracker/jira.rb
46
+ - lib/tracker/trac.rb
47
+ - lib/tracker/xforge.rb
48
+ - lib/tracker/jira/host.rb
49
+ - lib/tracker/jira/project.rb
50
+ - lib/tracker/trac/project.rb
51
+ - lib/tracker/xforge/base.rb
52
+ - lib/tracker/xforge/rubyforge.rb
46
53
  - lib/xforge/host.rb
47
54
  - lib/xforge/project.rb
48
55
  - lib/xforge/rubyforge.rb
@@ -61,7 +68,6 @@ rdoc_options:
61
68
  extra_rdoc_files:
62
69
  - README
63
70
  - MIT-LICENSE
64
- - TODO
65
71
  - CHANGES
66
72
  executables: []
67
73
  extensions: []
@@ -1,63 +0,0 @@
1
- module Tracker
2
- class RubyForge
3
- attr_reader :uri, :project
4
-
5
- def initialize(uri, project)
6
- @uri, @project = uri, project
7
- end
8
-
9
- def issue(identifier)
10
- sub_trackers = atids.collect {|atid| SubTracker.new(self, atid)}
11
- sub_trackers.each do |sub_tracker|
12
- issue = sub_tracker.issue(identifier)
13
- return issue unless issue.nil?
14
- end
15
- nil
16
- end
17
-
18
- class SubTracker
19
- attr_reader :uri
20
-
21
- def initialize(rubyforge, atid)
22
- @rubyforge = rubyforge
23
- @atid = atid
24
- # FIXME: This will only show open items.
25
- @uri = "#{rubyforge.uri}&atid=#{atid}&func=browse"
26
- end
27
-
28
- def issue(identifier)
29
- html = open(uri) { |data| data.read }
30
-
31
- regexp = /<a href=\"\/tracker\/index.php\?func=detail&aid=#{identifier}&group_id=\d+&atid=\d+\">(.*)<\/a>/
32
- if(html =~ regexp)
33
- issue_uri = @rubyforge.project.group_id_uri("tracker/index.php", "&atid=#{@atid}&func=detail&aid=#{identifier}")
34
- return Issue.new(issue_uri, $1)
35
- end
36
- nil
37
- end
38
- end
39
-
40
- private
41
-
42
- # The ids of the subtrackers
43
- def atids
44
- html = open(uri) { |data| data.read }
45
-
46
- # TODO: there has to be a better way to extract the atids from the HTML!
47
- atids = []
48
- offset = 0
49
- look_for_atid = true
50
- while(look_for_atid)
51
- match_data = /\/tracker\/\?atid=(\d+)&group_id=\d*&func=browse/.match(html[offset..-1])
52
- if(match_data)
53
- offset += match_data.begin(1)
54
- atids << match_data[1]
55
- else
56
- look_for_atid = false
57
- end
58
- end
59
- atids
60
- end
61
-
62
- end
63
- end