rscm 0.2.1.1404 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/README +34 -23
  2. data/Rakefile +24 -29
  3. data/bin/touch.exe +0 -0
  4. data/lib/rscm.rb +6 -3
  5. data/lib/rscm/annotations.rb +26 -7
  6. data/lib/rscm/{abstract_scm.rb → base.rb} +109 -71
  7. data/lib/rscm/better.rb +16 -0
  8. data/lib/rscm/logging.rb +11 -5
  9. data/lib/rscm/path_converter.rb +9 -16
  10. data/lib/rscm/revision.rb +201 -0
  11. data/lib/rscm/revision_file.rb +71 -0
  12. data/lib/rscm/scm/clearcase.rb +7 -7
  13. data/lib/rscm/scm/cvs.rb +69 -70
  14. data/lib/rscm/scm/cvs_log_parser.rb +29 -29
  15. data/lib/rscm/scm/darcs.rb +82 -34
  16. data/lib/rscm/scm/darcs_log_parser.rb +65 -0
  17. data/lib/rscm/scm/monotone.rb +249 -77
  18. data/lib/rscm/scm/monotone_log_parser.rb +57 -43
  19. data/lib/rscm/scm/mooky.rb +3 -3
  20. data/lib/rscm/scm/perforce.rb +196 -134
  21. data/lib/rscm/scm/star_team.rb +10 -10
  22. data/lib/rscm/scm/subversion.rb +106 -77
  23. data/lib/rscm/scm/subversion_log_parser.rb +76 -47
  24. data/lib/rscm/time_ext.rb +2 -116
  25. data/test/rscm/annotations_test.rb +15 -2
  26. data/test/rscm/{abstract_scm_test.rb → base_test.rb} +3 -3
  27. data/test/rscm/difftool_test.rb +9 -3
  28. data/test/rscm/generic_scm_tests.rb +195 -124
  29. data/test/rscm/revision_fixture.rb +20 -0
  30. data/test/rscm/revision_test.rb +129 -0
  31. data/test/rscm/{changesets.yaml → revisions.yaml} +10 -10
  32. data/test/rscm/scm/clearcase.log +608 -0
  33. data/test/rscm/scm/clearcase_test.rb +39 -0
  34. data/test/rscm/scm/cvs_log_parser_test.rb +73 -73
  35. data/test/rscm/scm/cvs_test.rb +1 -1
  36. data/test/rscm/scm/darcs_log_parser_test.rb +171 -0
  37. data/test/rscm/scm/monotone_log_parser_test.rb +49 -31
  38. data/test/rscm/scm/monotone_test.rb +3 -2
  39. data/test/rscm/scm/p4client_test.rb +33 -0
  40. data/test/rscm/scm/perforce_test.rb +25 -3
  41. data/test/rscm/scm/star_team.rb +9 -9
  42. data/test/rscm/scm/subversion_log_parser_test.rb +107 -47
  43. metadata +17 -13
  44. data/lib/multipart.rb +0 -95
  45. data/lib/rscm/RSS.txt +0 -41
  46. data/lib/rscm/changes.rb +0 -268
  47. data/lib/rscm/example.yaml +0 -21
  48. data/lib/rubyforge_file_publisher.rb +0 -176
  49. data/test/rscm/changes_fixture.rb +0 -20
  50. data/test/rscm/changes_test.rb +0 -129
@@ -1,95 +0,0 @@
1
- require 'open-uri'
2
- require 'net/http'
3
- require 'cgi'
4
-
5
- # Adds multipart support to Net::HTTP
6
- # based on Code from Patrick May
7
- # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/113774
8
- module Net
9
- class Param
10
- def initialize(k, v)
11
- @k = k
12
- @v = v
13
- end
14
-
15
- def to_multipart
16
- "Content-Disposition: form-data; name=\"#{CGI::escape(@k)}\"\r\n\r\n#{@v}\r\n"
17
- end
18
- end
19
-
20
- class FileParam
21
- def initialize(k, file, mime_type)
22
- @k = k
23
- @file = file
24
- @mime_type = mime_type
25
- end
26
-
27
- def to_multipart
28
- content = File.open(@file).read
29
- "Content-Disposition: form-data; name=\"#{CGI::escape(@k)}\"; filename=\"#{File.basename(@file)}\"\r\n" +
30
- "Content-Type: #{@mime_type}\r\n\r\n" + content + "\r\n"
31
- end
32
- end
33
-
34
- class HTTP
35
-
36
- def post_multipart(path, params, header={}, dest=nil, boundary="----------ThIs_Is_tHe_bouNdaRY_$") # :yield: self
37
- body = params.collect { |p|
38
- "--" + boundary + "\r\n" + p.to_multipart
39
- }.join("") + "--" + boundary + "--" + "\r\n"
40
-
41
- header["Content-Type"] = "multipart/form-data; boundary=" + boundary
42
- header["Content-Length"] = "#{body.length}"
43
-
44
- post(path, body, header, dest)
45
- end
46
-
47
- alias :old_post :post
48
- def post(path, data, initheader = nil, dest = nil)
49
- puts "----POST----"
50
- puts path
51
- puts "------------"
52
- if(initheader)
53
- initheader.each {|k,v|
54
- puts "#{k}: #{v}"
55
- }
56
- end
57
- puts
58
- puts data
59
-
60
- response, data = old_post(path, data, initheader, dest)
61
-
62
- puts "----POST RESP----"
63
- puts response.class.name
64
- puts "------------"
65
- response.each {|k,v|
66
- puts "#{k}: #{v}"
67
- }
68
-
69
- return response, data
70
- end
71
-
72
- alias :old_get :get
73
- def get(path, initheader = nil, dest = nil)
74
- puts "----GET-----"
75
- puts path
76
- puts "------------"
77
- if(initheader)
78
- initheader.each {|k,v|
79
- puts "#{k}: #{v}"
80
- }
81
- end
82
-
83
- response, data = old_get(path, initheader, dest)
84
-
85
- puts "----GET RESP----"
86
- puts response.class.name
87
- puts "------------"
88
- response.each {|k,v|
89
- puts "#{k}: #{v}"
90
- }
91
-
92
- return response, data
93
- end
94
- end
95
- end
@@ -1,41 +0,0 @@
1
- Sketch of RSS layout for DC and RSCM
2
-
3
- rss
4
- channel
5
- title:
6
- link:
7
- description:
8
- item
9
- pubDate:
10
- title:
11
- link:
12
- description
13
- xxx:
14
-
15
- rss
16
- channel
17
- title: PicoContainer Builds
18
- link: http://builds.codehaus.org/build/damagecontrol/project/picocontainer
19
- description: DamageControl build of PicoContainer
20
- item (one per build)
21
- pubDate: <dc_creation_time>
22
- title: PicoContainer Build FAILED
23
- link: http://builds.codehaus.org/build/damagecontrol/project/picocontainer/build/<dc_creation_time>
24
- description
25
- "Blurb about why it failed (tail from logs)"
26
- "who broke it (from changesets)"
27
- "Changesets"
28
-
29
- rss
30
- channel
31
- title: PicoContainer CVS
32
- link: http://cvs.picocontainer.org/
33
- description: Changesets for PicoContainer (viewcvs/fisheye etc)
34
- item (one per changeset)
35
- pubDate: <changeset_time>
36
- title: changeset commit message (trunkated - w/o links)
37
- link: Link to changeset page (if supported - fisheye etc). otherwise to root of scm_web
38
- description
39
- "changeset message with tracker URLs (newline-escaped)"
40
- "|revision|path (with links)|"
41
-
@@ -1,268 +0,0 @@
1
- require 'xmlrpc/utils'
2
- require 'rscm/time_ext'
3
-
4
- module RSCM
5
-
6
- # A collection of ChangeSet.
7
- class ChangeSets
8
- include Enumerable
9
- include XMLRPC::Marshallable
10
-
11
- attr_reader :changesets
12
-
13
- def initialize(changesets=[])
14
- @changesets = changesets
15
- end
16
-
17
- # Accepts a visitor that will receive callbacks while
18
- # iterating over this instance's internal structure.
19
- # The visitor should respond to the following methods:
20
- #
21
- # * visit_changesets(changesets)
22
- # * visit_changeset(changeset)
23
- # * visit_change(change)
24
- #
25
- def accept(visitor)
26
- visitor.visit_changesets(self)
27
- self.each{|changeset| changeset.accept(visitor)}
28
- end
29
-
30
- def [](change)
31
- @changesets[change]
32
- end
33
-
34
- def each(&block)
35
- @changesets.each(&block)
36
- end
37
-
38
- def reverse
39
- ChangeSets.new(@changesets.dup.reverse)
40
- end
41
-
42
- def length
43
- @changesets.length
44
- end
45
-
46
- def ==(other)
47
- return false if !other.is_a?(self.class)
48
- @changesets == other.changesets
49
- end
50
-
51
- def empty?
52
- @changesets.empty?
53
- end
54
-
55
- # The set of developers that contributed to all of the contained ChangeSet s.
56
- def developers
57
- result = []
58
- each do |changeset|
59
- result << changeset.developer unless result.index(changeset.developer)
60
- end
61
- result
62
- end
63
-
64
- # The latest ChangeSet (with the latest time)
65
- # or nil if there are none.
66
- def latest
67
- result = nil
68
- each do |changeset|
69
- result = changeset if result.nil? || result.time < changeset.time
70
- end
71
- result
72
- end
73
-
74
- # Adds a Change or a ChangeSet.
75
- # If the argument is a Change and no corresponding ChangeSet exists,
76
- # a new ChangeSet is created, added, and the Change is added to that ChangeSet -
77
- # and then finally the newly created ChangeSet is returned.
78
- # Otherwise nil is returned.
79
- def add(change_or_changeset)
80
- if(change_or_changeset.is_a?(ChangeSet))
81
- @changesets << change_or_changeset
82
- return change_or_changeset
83
- else
84
- changeset = @changesets.find { |a_changeset| a_changeset.can_contain?(change_or_changeset) }
85
- if(changeset.nil?)
86
- changeset = ChangeSet.new
87
- @changesets << changeset
88
- changeset << change_or_changeset
89
- return changeset
90
- end
91
- changeset << change_or_changeset
92
- return nil
93
- end
94
- end
95
-
96
- def push(*change_or_changesets)
97
- change_or_changesets.each { |change_or_changeset| self << (change_or_changeset) }
98
- self
99
- end
100
-
101
- # The most recent time of all the ChangeSet s.
102
- def time
103
- time = nil
104
- changesets.each do |changeset|
105
- time = changeset.time if @time.nil? || @time < changeset.time
106
- end
107
- time
108
- end
109
-
110
- # Sorts the changesets according to time
111
- def sort!
112
- @changesets.sort!
113
- self
114
- end
115
-
116
- end
117
-
118
- # Represents a collection of Change that were committed at the same time.
119
- # Non-transactional SCMs (such as CVS and StarTeam) emulate ChangeSet
120
- # by grouping Change s that were committed by the same developer, with the
121
- # same commit message, and within a "reasonably" small timespan.
122
- class ChangeSet
123
- include Enumerable
124
- include XMLRPC::Marshallable
125
-
126
- attr_reader :changes
127
- attr_accessor :revision
128
- attr_accessor :developer
129
- attr_accessor :message
130
- attr_accessor :time
131
-
132
- def initialize(changes=[])
133
- @changes = changes
134
- end
135
-
136
- def accept(visitor)
137
- visitor.visit_changeset(self)
138
- @changes.each{|change| change.accept(visitor)}
139
- end
140
-
141
- def << (change)
142
- @changes << change
143
- self.time = change.time if self.time.nil? || self.time < change.time unless change.time.nil?
144
- self.developer = change.developer if change.developer
145
- self.message = change.message if change.message
146
- end
147
-
148
- def [] (change)
149
- @changes[change]
150
- end
151
-
152
- def each(&block)
153
- @changes.each(&block)
154
- end
155
-
156
- def length
157
- @changes.length
158
- end
159
-
160
- def time=(t)
161
- raise "time must be a Time object - it was a #{t.class.name} with the string value #{t}" unless t.is_a?(Time)
162
- raise "can't set time to an inferiour value than the previous value" if @time && (t < @time)
163
- @time = t
164
- end
165
-
166
- def ==(other)
167
- return false if !other.is_a?(self.class)
168
- @changes == other.changes
169
- end
170
-
171
- def <=>(other)
172
- @time <=> other.time
173
- end
174
-
175
- # Whether this instance can contain a Change. Used
176
- # by non-transactional SCMs.
177
- def can_contain?(change)
178
- self.developer == change.developer &&
179
- self.message == change.message &&
180
- (self.time - change.time).abs < 60
181
- end
182
-
183
- # String representation that can be used for debugging.
184
- def to_s
185
- result = "#{revision} | #{developer} | #{time} | #{message}\n"
186
- self.each do |change|
187
- result << " " << change.to_s << "\n"
188
- end
189
- result
190
- end
191
-
192
- # Returns the identifier of the changeset. This is the revision
193
- # (if defined) or an UTC time if revision is undefined.
194
- def identifier
195
- @revision || @time
196
- end
197
-
198
- end
199
-
200
- # Represents a change to an individual file.
201
- class Change
202
- include XMLRPC::Marshallable
203
-
204
- MODIFIED = "MODIFIED"
205
- DELETED = "DELETED"
206
- ADDED = "ADDED"
207
- MOVED = "MOVED"
208
-
209
- attr_accessor :status
210
- attr_accessor :path
211
- attr_accessor :previous_revision
212
- attr_accessor :revision
213
-
214
- # TODO: Remove redundant attributes that are in ChangeSet
215
- attr_accessor :developer
216
- attr_accessor :message
217
- # This is a UTC ruby time
218
- attr_accessor :time
219
-
220
- def initialize(path=nil, status=nil, developer=nil, message=nil, revision=nil, time=nil)
221
- @path, @developer, @message, @revision, @time, @status = path, developer, message, revision, time, status
222
- end
223
-
224
- def accept(visitor)
225
- visitor.visit_change(self)
226
- end
227
-
228
- def to_s
229
- "#{path} | #{revision}"
230
- end
231
-
232
- def developer=(developer)
233
- raise "can't be null" if developer.nil?
234
- @developer = developer
235
- end
236
-
237
- def message=(message)
238
- raise "can't be null" if message.nil?
239
- @message = message
240
- end
241
-
242
- def path=(path)
243
- raise "can't be null" if path.nil?
244
- @path = path
245
- end
246
-
247
- def revision=(revision)
248
- raise "can't be null" if revision.nil?
249
- @revision = revision
250
- end
251
-
252
- def time=(time)
253
- raise "time must be a Time object" unless time.is_a?(Time)
254
- @time = time
255
- end
256
-
257
- def ==(other)
258
- return false if !other.is_a?(self.class)
259
- self.path == other.path &&
260
- self.developer == other.developer &&
261
- self.message == other.message &&
262
- self.revision == other.revision &&
263
- self.time == other.time
264
- end
265
-
266
- end
267
-
268
- end
@@ -1,21 +0,0 @@
1
- --- !ruby/object:RSCM::RssService
2
- rss_file: target/ngst.xml
3
- title: NGST Changesets
4
- url: http://damagecontrol.codehaus.org/
5
- description: StarTeam changes for NGST
6
- checkout_dir: target/ngst
7
- interval: 10
8
- port: 9090
9
- scm: !ruby/object:RSCM::StarTeam
10
- st_user_name: jimmitchell
11
- st_password: gandalf1
12
- st_server_name: "192.168.254.21"
13
- st_server_port: 49201
14
- st_project_name: "NGST Application"
15
- st_view_name: "NGST Application"
16
- st_folder_name: "java"
17
- scm_web: !ruby/object:RSCM::SCMWeb::ViewCVS
18
- view_cvs_url: http://cvs.damagecontrol.codehaus.org/
19
- tracker: !ruby/object:RSCM::Tracker::JIRA
20
- jira_project_id: NGST
21
- jira_url: http://jira.ctcdcx.local:8080/
@@ -1,176 +0,0 @@
1
- # Copyright 2005 by Aslak Hellesoy (aslak.hellesoy@gmail.com)
2
- # All rights reserved.
3
- #
4
- # Permission is granted for use, copying, modification, distribution,
5
- # and distribution of modified versions of this work as long as the
6
- # above copyright notice is included.
7
-
8
- require 'lib/multipart'
9
-
10
- module Rake
11
-
12
- # This publisher allows scripted submission of RubyForge's release files form.
13
- class RubyForgeFilePublisher
14
- # extension => [mime_type, rubyforge_bin_type_id, rubyforge_src_type_id]
15
- FILE_TYPES = Hash.new(["application/octet-stream", 9999, 5900]) # default to "other", "other source"
16
- FILE_TYPES.merge!(
17
- ".deb" => ["application/octet-stream", 1000],
18
-
19
- # all of these can be source or binary
20
- ".rpm" => ["application/octet-stream", 2000, 5100],
21
- ".zip" => ["application/octet-stream", 3000, 5000],
22
- ".bz2" => ["application/octet-stream", 3100, 5010],
23
- ".gz" => ["application/octet-stream", 3110, 5020],
24
- ".jpg" => ["application/octet-stream", 8000],
25
- ".jpeg" => ["application/octet-stream", 8000],
26
- ".txt" => ["text/plain", 8100],
27
- ".html" => ["text/html", 8200],
28
- ".pdf" => ["application/octet-stream", 8300],
29
- ".ebuild" => ["application/octet-stream", 1300],
30
- ".exe" => ["application/octet-stream", 1100],
31
- ".dmg" => ["application/octet-stream", 1200],
32
- ".gem" => ["application/octet-stream", 1400],
33
- ".sig" => ["application/octet-stream", 8150]
34
- )
35
-
36
- # Returns an array of 2 elements where 1st is mime-type and 2nd is rubyforge-type
37
- def types(filename, source)
38
- extension = nil
39
- if(filename =~ /.*(\.[a-zA-Z]*)/)
40
- extension = $1
41
- end
42
-
43
- types = FILE_TYPES[extension]
44
- if(types.length == 3 && source)
45
- [types[0], types[2]]
46
- else
47
- types
48
- end
49
- end
50
-
51
- # processor_id
52
- I386 = 1000
53
- IA64 = 6000
54
- ALPHA = 7000
55
- ANY = 8000
56
- PPC = 2000
57
- MIPS = 3000
58
- SPARC = 4000
59
- ULTRA_SPARC = 5000
60
- OTHER_PLATFORM = 9999
61
-
62
- # Create a publisher for a RubyForge project with id +group_id+.
63
- # The RubyForge +user+'s password must be specified in the environment
64
- # variable RUBYFORGE_PASSWORD.
65
- #
66
- # This publisher will upload/release a +file+ for a RubyForge project
67
- # with id +group_id+, under the release package +package_id+ and
68
- # name the release +release_name+.
69
- #
70
- # The package_id can be found by viewing the source of the HTML page
71
- # http://rubyforge.org/frs/admin/qrs.php?package=&group_id=YOUR_GROUP_ID
72
- # Look for a select tag named package_id and see what the alternatives are.
73
- #
74
- # The optional argument +source+ can be set to true if the file
75
- # pointed to by +filename+ is a source file of some sort. This is
76
- # to make sure RubyForge lists the file as the appropriate type.
77
- # (This task will figure out the correct mime-type and rubyforge type
78
- # based on the file's extension and the source parameter).
79
- #
80
- # If called with a block, the file will be uploaded at the end of the
81
- # construction of this object. Otherwise, the +upload+ method will
82
- # have to be called explicitly.
83
- #
84
- # The following attributes (which represent form data) have default
85
- # values, but can be set/overridden explicitly:
86
- #
87
- # * processor_id
88
- # * release_date
89
- # * release_notes
90
- # * change_log
91
- #
92
- def initialize(group_id, user, file, package_id, release_name, source=false) # :yield: self
93
-
94
- @group_id = group_id
95
- @user = user
96
- @file = file
97
-
98
- @form_data = {"preformatted" => "1", "submit" => "Release File" }
99
-
100
- self.package_id = package_id
101
- self.release_name = release_name
102
-
103
- @types = types(file, source)
104
- self.type_id = @types[1]
105
- self.processor_id = ANY
106
- self.release_date = Time.now.utc
107
- self.release_notes = "Uploaded by Rake::RubyforgeFilePublisher"
108
- self.release_changes = "This is a change log"
109
-
110
- yield self if block_given?
111
- upload if block_given?
112
- end
113
-
114
- def package_id=(s)
115
- @form_data["package_id"] = s
116
- end
117
- def package_id
118
- @form_data["package_id"]
119
- end
120
- def release_name=(s)
121
- @form_data["release_name"] = s
122
- end
123
- def type_id=(s)
124
- @form_data["type_id"] = s
125
- end
126
- def processor_id=(s)
127
- @form_data["processor_id"] = s
128
- end
129
- def release_date=(t)
130
- @form_data["release_date"] = t.strftime("%Y-%m-%d %H:%M")
131
- end
132
- def release_notes=(s)
133
- @form_data["release_notes"] = s
134
- end
135
- def release_changes=(s)
136
- @form_data["release_changes"] = s
137
- end
138
- def preformatted=(b)
139
- @form_data["preformatted"] = b ? "1" : "0"
140
- end
141
-
142
- def upload
143
- Net::HTTP.start('rubyforge.org', 80) do |http|
144
-
145
- # log in so we get a cookie. we need it to post the upload form.
146
- password = ENV['RUBYFORGE_PASSWORD']
147
- raise "The RUBYFORGE_PASSWORD environment variable is not set.\n" +
148
- "It can be passed on the Rake command line with RUBYFORGE_PASSWORD=<your password>" if password.nil?
149
-
150
- response, data = http.post("/account/login.php", "form_loginname=#{@user}&form_pw=#{password}&login=Login")
151
- cookie = CGI::Cookie.parse(response['set-cookie'])['session_ser'].to_s
152
- header = {"Cookie" => cookie, "Host" => "rubyforge.org"}
153
-
154
- response, data = http.get(response['location'], header)
155
-
156
- upload_form = "/frs/admin/qrs.php?package=#{package_id}&group_id=#{@group_id}"
157
- response, data = http.get(upload_form, header)
158
-
159
- params = []
160
- @form_data.each do |k, v|
161
- params << Net::Param.new(k,v)
162
- end
163
- params << Net::FileParam.new("userfile", @file, @types[0])
164
- header["Referer"] = "http://rubyforge.org#{upload_form}"
165
- response, data = http.post_multipart(upload_form, params, header)
166
-
167
- File.open("rf.html", "w") { |io|
168
- io.write data
169
- }
170
- # upload_redirect = response['location']
171
- # response, data = http.get(upload_redirect, header)
172
- end
173
- end
174
-
175
- end
176
- end