meta_project 0.4.3 → 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,12 +1,24 @@
1
- = XForge Changelog
1
+ = MetaProject Changelog
2
+
3
+ == Version 0.4.4
4
+
5
+ This release introduces a new Domain Specific Language (DSL) for SCM commit messages similar to Trac's post-commit hook for updating tickets.
6
+ Patois is supported in a tracker-agnostic way (although it's only half implemented for JIRA only ATM).
7
+ There is also initial support for FreshMeat and RAA thanks to Thomas Leitner.
8
+
9
+ * Added support for Patois parsing (See RubyDoc).
10
+ * Gave the Patois DSL its name.
11
+ * Improved the Tracker::Issue API to be more OO and uniform across trackers.
12
+ * Adds support for FreshMeat and RAA (Fixes #2323). This is not aligned with the rest of the MetaProject API yet.
2
13
 
3
14
  == Version 0.4.3
4
15
 
5
- This is a bugfix release.
16
+ This release fixes some bugs and implements some new issue tracker features.
6
17
 
7
18
  * Aligned properties between TracTracker and JiraTracker with ProjectAnalyzer.
8
19
  * Stripping leading and trailing whitespace from issue summaries (SF seems to have changed).
9
20
  * Added name to XForge projects.
21
+ * Added create_issue to JiraTracker.
10
22
 
11
23
  == Version 0.4.2
12
24
 
data/Rakefile CHANGED
@@ -24,7 +24,7 @@ require 'rake/rdoctask'
24
24
  #
25
25
  # REMEMBER TO KEEP PKG_VERSION IN SYNC WITH THE CHANGES FILE!
26
26
  PKG_NAME = "meta_project"
27
- PKG_VERSION = "0.4.3"
27
+ PKG_VERSION = "0.4.4"
28
28
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
29
29
  PKG_FILES = FileList[
30
30
  '[A-Z]*',
@@ -0,0 +1,99 @@
1
+ module MetaProject
2
+ # Patois is a domain specific language (DSL)
3
+ # for configuration and release management. It was first implemented by
4
+ # <a href="http://projects.edgewall.com/trac/browser/trunk/contrib/trac-post-commit-hook">Trac</a>
5
+ # and this class is a Ruby port of that Python code.
6
+ #
7
+ # A similar idea was created by the DamageControl team in <a href="http://jira.codehaus.org/browse/DC-159">DC-159</a>
8
+ # before it was implemented in Trac, but the Trac team beat the DamageControl to implement it.
9
+ #
10
+ # Anyhow, by giving this mini DSL a name and some better profiling we hope its adoption
11
+ # will increase. Patois means:
12
+ #
13
+ # * a dialect other than the standard or literary dialect
14
+ # * uneducated or provincial speech
15
+ # * the characteristic special language of an occupational or social group
16
+ #
17
+ # Patois' intended usage is in SCM commit messages. A patois-aware system can parse the commit
18
+ # messages and try to recognise patois expressions and take appropriate actions.
19
+ #
20
+ # Here is a little taste of what you can say and do with Patois.
21
+ #
22
+ # == General form
23
+ #
24
+ # command #1
25
+ # command #1, #2
26
+ # command #1 & #2
27
+ # command #1 and #2 # == Closing issues in an issue tracker
28
+ #
29
+ # You can have more than one command in a message. The following commands
30
+ # are supported. There is more than one spelling for each command, to make
31
+ # this as user-friendly as possible.
32
+ #
33
+ # close, closed, closes, fix, fixed, fixes
34
+ # The specified issues are closed with the contents of the
35
+ # commit message being added to it.
36
+ #
37
+ # addresses, re, ref, references, refs, see
38
+ # The specified issues are left in their current status, but
39
+ # the contents of the commit message are added to their notes.
40
+ #
41
+ # A fairly complicated example of what you can do is with a commit message
42
+ # of:
43
+ #
44
+ # Changed blah and foo to do this or that. Fixes #10 and #12, and refs #12.
45
+ #
46
+ # This will close #10 and #12, and add a note to #12
47
+ #
48
+ module Patois
49
+
50
+ # Parses Patois
51
+ #
52
+ class Parser
53
+
54
+ SUPPORTED_COMMANDS = {
55
+ 'close' => ':close',
56
+ 'closed' => ':close',
57
+ 'closes' => ':close',
58
+ 'fix' => ':close',
59
+ 'fixed' => ':close',
60
+ 'fixes' => ':close',
61
+ 'addresses' => ':comment',
62
+ 're' => ':comment',
63
+ 'ref' => ':comment',
64
+ 'references' => ':comment',
65
+ 'refs' => ':comment',
66
+ 'see' => ':comment'
67
+ }
68
+
69
+ # Creates a new parser that will parse commands with +command_pattern+
70
+ # and emit individual commands with +issue_pattern+.
71
+ def initialize(command_pattern, issue_pattern)
72
+ @command_pattern = command_pattern
73
+ @issue_pattern = issue_pattern
74
+ end
75
+
76
+ # Parses a patois String and yields commands.
77
+ # Each operation can be executed with +execute+
78
+ def parse(msg)
79
+ msg.scan(@command_pattern) do |cmd_group|
80
+ cmd = SUPPORTED_COMMANDS[cmd_group[0].downcase]
81
+ if(cmd)
82
+ cmd_group[1].scan(@issue_pattern) do |issue_id_array|
83
+ yield Command.new(cmd, issue_id_array[0].upcase, msg)
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ class Command
90
+
91
+ attr_reader :cmd, :issue_id, :msg
92
+
93
+ def initialize(cmd, issue_id, msg)
94
+ @cmd, @issue_id, @msg = cmd, issue_id, msg
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1 @@
1
+ require 'meta_project/patois/parser'
@@ -46,7 +46,7 @@ module MetaProject
46
46
  def group_id
47
47
  unless(@group_id)
48
48
  regexp = /stats\/[?&]group_id=(\d+)/
49
- html = open(xforge_project_url) { |data| data.read }
49
+ html = open(xforge_project_url).read
50
50
  @group_id = html[regexp, 1]
51
51
  raise "Couldn't get group_id" unless @group_id
52
52
  end
@@ -64,7 +64,7 @@ module MetaProject
64
64
  # The home page of this project
65
65
  def home_page
66
66
  unless(@home_page)
67
- html = open(xforge_project_url) { |data| data.read }
67
+ html = open(xforge_project_url).read
68
68
  @home_page = html[home_page_regexp, 1]
69
69
  raise "Couldn't get home_page" unless @home_page
70
70
  end
@@ -0,0 +1,267 @@
1
+ # Copyright (C) 2005 Thomas Leitner
2
+ #
3
+ # See LICENCE for details
4
+
5
+ require "xmlrpc/client"
6
+ require 'yaml'
7
+
8
+ module DevTools
9
+
10
+ module Freshmeat
11
+
12
+ class FreshmeatException < StandardError; end
13
+
14
+ # Describes a freshmeat project.
15
+ class Project
16
+
17
+ # The short name of the project
18
+ attr_reader :shortName
19
+
20
+ # The full name of the project
21
+ attr_reader :fullName
22
+
23
+ # The status of the project (alpha, beta, ...)
24
+ attr_reader :status
25
+
26
+ # The current version string of the project
27
+ attr_reader :version
28
+
29
+ def initialize( shortName, fullName, status, version )
30
+ @shortName, @fullName, @status, @version = shortName, fullName, status, version
31
+ end
32
+
33
+ def to_s
34
+ "Project: short name = #{@shortName}, full name = #{@fullName}, status = #{@status}, version = #{@version}"
35
+ end
36
+
37
+ end
38
+
39
+ # Provides information about a release.
40
+ class ReleaseInfo
41
+
42
+ # Version string of release
43
+ attr_reader :version
44
+
45
+ # Change list of release
46
+ attr_reader :changes
47
+
48
+ # Release focus
49
+ attr_reader :release_focus
50
+
51
+ # True, if hidden from frontpage
52
+ attr_reader :hidden
53
+
54
+ # Returns a new ReleaseInfo object
55
+ def initialize( version, changes, release_focus, hidden )
56
+ @version, @changes, @release_focus, @hidden = version, changes, release_focus, hidden
57
+ end
58
+
59
+ def to_s
60
+ "ReleaseInfo: version = #{@version}, release focus = #{ReleaseFocusID::NAMES[@release_focus]}, hidden = #{hidden}\nChanges = #{@changes}"
61
+ end
62
+
63
+ end
64
+
65
+ # Holds all information about a release which should be published.
66
+ class Release
67
+
68
+ #Project name to submit a release for
69
+ attr_accessor :project_name
70
+
71
+ #Branch name to submit a release for
72
+ attr_accessor :branch_name
73
+
74
+ #Version string of new release
75
+ attr_accessor :version
76
+
77
+ #Changes list, no HTML, character limit 600 chars
78
+ attr_accessor :changes
79
+
80
+ #Release focus ID of new release
81
+ attr_accessor :release_focus
82
+
83
+ #Set to 'Y' if release is to be hidden from frontpage, everything else does not hide it
84
+ attr_accessor :hide_from_frontpage
85
+
86
+ #Optional: Branch license
87
+ attr_accessor :license
88
+
89
+ #Optional: Homepage
90
+ attr_accessor :url_homepage
91
+
92
+ #Optional: Tar/GZ
93
+ attr_accessor :url_tgz
94
+
95
+ #Optional: Tar/BZ2
96
+ attr_accessor :url_bz2
97
+
98
+ #Optional: Zip
99
+ attr_accessor :url_zip
100
+
101
+ #Optional: Changelog
102
+ attr_accessor :url_changelog
103
+
104
+ #Optional: RPM package
105
+ attr_accessor :url_rpm
106
+
107
+ #Optional: Debian package
108
+ attr_accessor :url_deb
109
+
110
+ #Optional: OS X package
111
+ attr_accessor :url_osx
112
+
113
+ #Optional: BSD Ports URL
114
+ attr_accessor :url_bsdport
115
+
116
+ #Optional: Purchase
117
+ attr_accessor :url_purchase
118
+
119
+ #Optional: CVS tree (cvsweb)
120
+ attr_accessor :url_cvs
121
+
122
+ #Optional: Mailing list archive
123
+ attr_accessor :url_list
124
+
125
+ #Optional: Mirror site
126
+ attr_accessor :url_mirror
127
+
128
+ #Optional: Demo site
129
+ attr_accessor :url_demo
130
+
131
+ def self.from_data( data=nil )
132
+ YAML::load( data )
133
+ end
134
+
135
+ def to_rpc_data
136
+ rpc_data = {}
137
+ instance_variables.each do |iv|
138
+ rpc_data[iv[1..-1]] = eval( iv )
139
+ end
140
+ rpc_data
141
+ end
142
+
143
+ def to_yaml_type
144
+ "!thomasleitner,2005/FreshmeatRelease"
145
+ end
146
+
147
+ YAML::add_domain_type( 'thomasleitner,2005', 'FreshmeatRelease' ) do |type, val|
148
+ YAML::object_maker( Release, val )
149
+ end
150
+
151
+ end
152
+
153
+ # Provides constants for all release focus ids
154
+ module ReleaseFocusID
155
+ NA = 0
156
+ INITIAL_ANNOUNCEMENT = 1
157
+ DOCUMENTATION = 2
158
+ CODE_CLEANUP = 3
159
+ MINOR_FEATURES = 4
160
+ MAJOR_FEATURES = 5
161
+ MINOR_BUGFIXES = 6
162
+ MAJOR_BUGFIXES = 7
163
+ MINOR_SECFIXES = 8
164
+ MAJOR_SECFIXES = 9
165
+
166
+ NAMES = {0=>'N/A',
167
+ 1=>'Initial freshmeat announcement',
168
+ 2=>'Documentation',
169
+ 3=>'Code cleanup',
170
+ 4=>'Minor feature enhancements',
171
+ 5=>'Major feature enhancements',
172
+ 6=>'Minor bugfixes',
173
+ 7=>'Major bugfixes',
174
+ 8=>'Minor security fixes',
175
+ 9=>'Major security fixes'
176
+ }
177
+ end
178
+
179
+
180
+ # Provides access to the Freshmeat XML-RPC API via a nice interface.
181
+ # API reference at http://freshmeat.net/faq/view/49/
182
+ #
183
+ # Example:
184
+ #
185
+ # fm = DevTools::FreshmeatService.new( username, password )
186
+ # fm.get_project_list.each do |p|
187
+ # puts p
188
+ # branches = fm.get_branch_list( p.shortName )
189
+ # puts branches.inspect
190
+ # release = fm.get_release( p.shortName, branches[0], p.version )
191
+ # puts release
192
+ # end
193
+ # puts fm.logout
194
+ class FreshmeatService
195
+
196
+ # The URL for the Freshmeat RPC service
197
+ RPCURL = 'http://freshmeat.net/xmlrpc/'
198
+
199
+ # The major version of the freshmeat API with which this library works
200
+ API_VERSION_MAJOR = '1'
201
+
202
+ # The minor version of the freshmeat API with which this library works
203
+ API_VERSION_MINOR = '03'
204
+
205
+ # Use +username+ and +password+ to log into Freshmeat service.
206
+ def initialize( username, password )
207
+ @session = XMLRPC::Client.new2( RPCURL )
208
+ ret = @session.call( :login, :username=>username, :password=>password )
209
+ @sid = ret['SID']
210
+ major, minor = ret['API Version'].split( '.' )
211
+ if major != API_VERSION_MAJOR or minor < API_VERSION_MINOR
212
+ raise FreshmeatException, 'Incompatible API versions'
213
+ end
214
+ end
215
+
216
+ # Returns all available licenses
217
+ def self.get_licenses
218
+ XMLRPC::Client.new2( RPCURL ).call( :fetch_available_licenses )
219
+ end
220
+
221
+ # Returns all available release focus types
222
+ def self.get_release_focus_types
223
+ XMLRPC::Client.new2( RPCURL ).call( :fetch_available_release_foci )
224
+ end
225
+
226
+ # Returns an array of Project objects which are assigned to the logged in user
227
+ def get_project_list
228
+ ret = @session.call( :fetch_project_list, :SID=>@sid )
229
+ ret.collect! {|p| Project.new( p['projectname_short'], p['projectname_full'], p['project_status'], p['project_version'] ) }
230
+ end
231
+
232
+ # Returns an array of branch names for the project +project+.
233
+ def get_branch_list( project )
234
+ @session.call( :fetch_branch_list, :SID=>@sid, :project_name=>project )
235
+ end
236
+
237
+ # Returns a ReleaseInfo object which has the information about the requested release.
238
+ def get_release( project, branch, version )
239
+ ret = @session.call( :fetch_release, :SID=>@sid, :project_name=>project, :branch_name=>branch, :version=>version )
240
+ releaseFocus = ret['release_focus'].split( ' - ' )[0].to_i
241
+ hidden = (ret['hide_from_frontpage'] == 'Y' )
242
+ ReleaseInfo.new( ret['version'], ret['changes'], releaseFocus, hidden )
243
+ end
244
+
245
+ # Publishes a new release of a project. The parameter +release+ has to be a Release object!
246
+ def publish_release( release )
247
+ ret = @session.call( :publish_release, {:SID=>@sid}.update( release.to_rpc_data ) )
248
+ ret['OK'] == 'submission successful'
249
+ end
250
+
251
+ # Withdraws the specified release.
252
+ def withdraw_release( project, branch, version )
253
+ ret = @session.call( :withdraw_release, :SID=>@sid, :project_name=>project, :branch_name=>branch, :version=>version )
254
+ ret['OK'] == 'Withdraw successful.'
255
+ end
256
+
257
+ # Logs out from the Freshmeat service.
258
+ def logout
259
+ ok, ret = @session.call2( :logout, :SID=>@sid )
260
+ ok && ret['OK'] == 'Logout successful.'
261
+ end
262
+
263
+ end
264
+
265
+ end
266
+
267
+ end