svn-command 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/ProjectInfo.rb +1 -1
- data/Readme +70 -66
- data/lib/svn-command/subversion.rb +95 -9
- data/lib/svn-command/subversion_extensions.rb +1 -1
- data/lib/svn-command/svn_command.rb +129 -24
- data/test/subversion_test.rb +44 -57
- data/test/svn_command_test.rb +45 -89
- data/test/test_helper.rb +3 -5
- metadata +2 -4
- data/test/shared/test_helper.rb +0 -5
- data/test/shared/test_helpers/test_colorizer.rb +0 -109
data/ProjectInfo.rb
CHANGED
@@ -5,7 +5,7 @@ module Project
|
|
5
5
|
PrettyName = "Enhanced Subversion Command"
|
6
6
|
Name = "svn-command"
|
7
7
|
RubyForgeName = "svn-command"
|
8
|
-
Version = "0.2.
|
8
|
+
Version = "0.2.5"
|
9
9
|
Specification = Gem::Specification.new do |s|
|
10
10
|
s.name = Project::Name
|
11
11
|
s.summary = "A nifty wrapper command for Subversion's command-line svn client"
|
data/Readme
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
|
11
11
|
== Introduction
|
12
12
|
|
13
|
-
This is a replacement <tt>svn</tt>
|
13
|
+
This is a replacement <b><tt>svn</tt> command-line client</b> meant to be used instead of the standard +svn+ command. (Actually, it's a _wrapper_, not a replacement, because it still uses <tt>/usr/bin/svn</tt> to do all the dirty work.)
|
14
14
|
|
15
15
|
== Installation
|
16
16
|
|
@@ -46,33 +46,70 @@ You'll know it's working by way of two signs:
|
|
46
46
|
== Features
|
47
47
|
|
48
48
|
Changes to existing subcommands:
|
49
|
-
* <tt>svn diff</tt>
|
49
|
+
* <b><tt>svn diff</tt></b>
|
50
50
|
* output is in _color_* (requires +colordiff+, see below)
|
51
51
|
* <tt>svn diff</tt> includes the differences from your *externals* too (consistent with how <tt>svn status</tt> includes them) so that you don't forget to commit those changes too! (pass <tt>--ignore-externals</tt> if you _don't_ want a diff of externals)
|
52
|
-
* <tt>svn status</tt>
|
52
|
+
* <b><tt>svn status</tt></b>
|
53
53
|
* filters out distracting, useless output about externals (don't worry -- it still shows which files were _modified_)
|
54
54
|
* the flags (?, M, C, etc.) are in *color*!
|
55
|
-
* <tt>svn move</tt> it will let you move multiple source files to a destination directory with a single command
|
55
|
+
* <b><tt>svn move</tt></b> it will let you move multiple source files to a destination directory with a single command
|
56
56
|
|
57
57
|
(* You can pass --no-color to disable colors for a single command...useful if you want to pipe the output to another command or something. Eventually maybe we could make this a per-user option via .svn-command?)
|
58
58
|
|
59
59
|
New subcommands:
|
60
|
-
* <tt>svn each_unadded</tt> (+eu+, +unadded+) -- goes through each unadded (<tt>?</tt>) file reported by <tt>svn status</tt> and asks you what to do with them (add, delete, ignore).
|
61
|
-
* <tt>svn
|
62
|
-
* <tt>svn
|
63
|
-
* <tt>svn edit_externals</tt> (+ee+)
|
64
|
-
* <tt>svn externalize</tt>
|
65
|
-
* <tt>svn set_message</tt> / <tt>svn get_message</tt> / <tt>svn edit_message</tt> -- shortcuts for accessing <tt>--revprop svn:log</tt>
|
66
|
-
* <tt>svn ignore</tt> -- shortcut for accessing <tt>svn:ignore</tt> property
|
67
|
-
* <tt>svn view_commits</tt> -- gives you output from both <tt>svn log</tt> and from <tt>svn diff</tt> for the given changesets (useful for code reviews)
|
68
|
-
* <tt>svn
|
69
|
-
* <tt>svn
|
60
|
+
* <b><tt>svn each_unadded</tt></b> (+eu+, +unadded+) -- goes through each unadded (<tt>?</tt>) file reported by <tt>svn status</tt> and asks you what to do with them (add, delete, ignore).
|
61
|
+
* <b><tt>svn revisions</tt></b> -- lists all revisions with log messages and lets you browse through them interactively
|
62
|
+
* <b><tt>svn externals</tt></b> -- lists all externals
|
63
|
+
* <b><tt>svn edit_externals</tt></b> (+ee+)
|
64
|
+
* <b><tt>svn externalize</tt></b>
|
65
|
+
* <b><tt>svn set_message</tt></b> / <tt>svn get_message</tt> / <tt>svn edit_message</tt> -- shortcuts for accessing <tt>--revprop svn:log</tt>
|
66
|
+
* <b><tt>svn ignore</tt></b> -- shortcut for accessing <tt>svn:ignore</tt> property
|
67
|
+
* <b><tt>svn view_commits</tt></b> -- gives you output from both <tt>svn log</tt> and from <tt>svn diff</tt> for the given changesets (useful for code reviews)
|
68
|
+
* <b><tt>svn url</tt></b> -- prints out the URL of the given working copy path or the curretn working copy
|
69
|
+
* <b><tt>svn repository_root</tt></b> -- prints out the root repository URL of the working copy you are in
|
70
|
+
* <b><tt>svn delete_svn</tt></b> -- causes the current directory (recursively) to no longer be a working copy
|
70
71
|
|
71
72
|
(RDoc question: how do I make the identifiers like Subversion::SvnCommand#externalize into links??)
|
72
73
|
|
73
74
|
= Usage / Examples
|
74
75
|
|
75
|
-
== <tt>svn
|
76
|
+
== <tt>svn each_unadded</tt>
|
77
|
+
|
78
|
+
My personal favorite. This command is useful for keeping your working copies clean -- getting rid of all those accumulated temp files (or *ignoring* or *adding* them if they're something that _all_ users of this repository should be aware of).
|
79
|
+
|
80
|
+
It simply goes through each "unadded" file (each file reporting a status of <tt>?</tt>) reported by <tt>svn status</tt> and asks you what you want to do with them -- *add*, *delete*, or *ignore*.
|
81
|
+
|
82
|
+
> svn each_unadded
|
83
|
+
|
84
|
+
What do you want to do with plugins/database_log4r/doc?
|
85
|
+
(shows preview)
|
86
|
+
(a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > i
|
87
|
+
Ignoring...
|
88
|
+
|
89
|
+
What do you want to do with applications/underlord/db/schema.rb?
|
90
|
+
(shows preview)
|
91
|
+
(a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > a
|
92
|
+
Adding...
|
93
|
+
|
94
|
+
What do you want to do with applications/underlord/vendor/plugins/exception_notification?
|
95
|
+
(shows preview)
|
96
|
+
(a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > d
|
97
|
+
Are you pretty much *SURE* you want to 'rm -rf applications/underlord/vendor/plugins/exception_notification'? (y)es, (n)o > y
|
98
|
+
Deleting...
|
99
|
+
|
100
|
+
For *files*, it will show a preview of the _contents_ of that file (limited to the first 55 lines); for *directories*, it will show a _directory_ _listing_. By looking at the preview, you should hopefully be able to decide whether you want to _keep_ the file or _junk_ it.
|
101
|
+
|
102
|
+
== <tt>svn revisions</tt> (revisions browser)
|
103
|
+
|
104
|
+
Lets you interactively step through all revisions of a file/directory/repository.
|
105
|
+
|
106
|
+
Screenshot:
|
107
|
+
link:include/svn_revisions.png
|
108
|
+
|
109
|
+
Use the <tt>--forwards</tt> flag if you want to <i>start at the oldest revision</i> and step forwards through time rather than starting at the latest revision and stepping backwards (the default).
|
110
|
+
|
111
|
+
|
112
|
+
== <tt>svn status</tt>
|
76
113
|
|
77
114
|
_Without_ this gem installed (really long):
|
78
115
|
|
@@ -112,32 +149,6 @@ _Without_ this gem installed (really long):
|
|
112
149
|
A gemables/subversion/bin/svn
|
113
150
|
M applications/underlord/vendor/plugins/rails_smith/tasks/shared/base.rake
|
114
151
|
|
115
|
-
== <tt>svn each_unadded</tt>
|
116
|
-
|
117
|
-
My personal favorite. This command is useful for keeping your working copies clean -- getting rid of all those accumulated temp files (or *ignoring* or *adding* them if they're something that _all_ users of this repository should be aware of).
|
118
|
-
|
119
|
-
It simply goes through each "unadded" file (each file reporting a status of <tt>?</tt>) reported by <tt>svn status</tt> and asks you what you want to do with them -- *add*, *delete*, or *ignore*.
|
120
|
-
|
121
|
-
> svn each_unadded
|
122
|
-
|
123
|
-
What do you want to do with plugins/database_log4r/doc?
|
124
|
-
(shows preview)
|
125
|
-
(a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > i
|
126
|
-
Ignoring...
|
127
|
-
|
128
|
-
What do you want to do with applications/underlord/db/schema.rb?
|
129
|
-
(shows preview)
|
130
|
-
(a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > a
|
131
|
-
Adding...
|
132
|
-
|
133
|
-
What do you want to do with applications/underlord/vendor/plugins/exception_notification?
|
134
|
-
(shows preview)
|
135
|
-
(a)dd, (d)elete, add to svn:(i)ignore property, or [Enter] to do nothing > d
|
136
|
-
Are you pretty much *SURE* you want to 'rm -rf applications/underlord/vendor/plugins/exception_notification'? (y)es, (n)o > y
|
137
|
-
Deleting...
|
138
|
-
|
139
|
-
For *files*, it will show a preview of the _contents_ of that file (limited to the first 55 lines); for *directories*, it will show a _directory_ _listing_. By looking at the preview, you should hopefully be able to decide whether you want to _keep_ the file or _junk_ it.
|
140
|
-
|
141
152
|
==<tt>svn externalize</tt> / <tt>externals</tt> / <tt>edit_externals</tt>
|
142
153
|
|
143
154
|
Shortcut for creating an svn:external...
|
@@ -202,17 +213,6 @@ You can now do commands like this:
|
|
202
213
|
|
203
214
|
(The _standard_ +svn+ command only accepts a _single_ source and a _single_ destination!)
|
204
215
|
|
205
|
-
== <tt>svn revisions</tt> (revisions browser)
|
206
|
-
|
207
|
-
Lets you interactively step through all revisions of a file/directory/repository.
|
208
|
-
|
209
|
-
|
210
|
-
Note: You may have to svn update your working copy in order for svn log (and hence svn revisions) to be able to see the revisions you just committed.
|
211
|
-
|
212
|
-
|
213
|
-
Use the <tt>--forwards</tt> flag if you want to <u>start at the oldest revision</u> and step forwards through time rather than starting at the latest revision and stepping backwards (the default).
|
214
|
-
|
215
|
-
|
216
216
|
== <tt>svn commit</tt>
|
217
217
|
|
218
218
|
=== --skip-notification / --covert
|
@@ -277,7 +277,7 @@ You can, of course, get a lits of the custom commands that have been added by us
|
|
277
277
|
* --print-commands (prints out the /usr/bin/svn commands before executing them)
|
278
278
|
* --debug (sets $debug = true)
|
279
279
|
|
280
|
-
|
280
|
+
==Requirement: <tt>colordiff</tt>
|
281
281
|
|
282
282
|
+colordiff+ is used to colorize <tt>svn diff</tt> commands (+ lines are blue; - lines are red)
|
283
283
|
|
@@ -292,6 +292,23 @@ Suggestion: change the colors in <tt>/etc/colordiffrc</tt> to be more readable:
|
|
292
292
|
diffstuff=cyan
|
293
293
|
cvsstuff=magenta
|
294
294
|
|
295
|
+
==A workaround for the <tt>Commit failed; Your file or directory 'some file' is probably out-of-date</tt> problem==
|
296
|
+
|
297
|
+
svn: Commit failed (details follow):
|
298
|
+
svn: Your file or directory 'some file' is probably out-of-date
|
299
|
+
svn: The version resource does not correspond to the resource within the transaction. Either the requested version resource is out of date (needs to be updated), or the requested version resource is newer than the transaction root (restart the commit).
|
300
|
+
Sending some file
|
301
|
+
(Doesn't actually finish the commit)
|
302
|
+
|
303
|
+
I'm still not sure what causes it (I didn't think I was doing anything _that_ out of the ordinary...) or how to _prevent_ it, because it keep happening to me (maybe I'm the only one?)... but I've at least automated the "fix" for this state somewhat.
|
304
|
+
|
305
|
+
The only way I've found to resolve this problem is to delete the entire directory and restore it (with svn update).
|
306
|
+
|
307
|
+
It must have something to do with something in the .svn directories not matching up the way that svn expects.
|
308
|
+
|
309
|
+
Anyway, the <tt>svn fix_out_of_date_commit_state</tt> command attempts to automate most of that process for you.
|
310
|
+
|
311
|
+
|
295
312
|
==Bash command completion
|
296
313
|
|
297
314
|
If you want command completion for the svn subcommands (and I don't blame you if you don't -- the default command completion is <i>much faster</i> and already gives you completion for filenames!), just add this line to your <tt>~/.bashrc</tt> :
|
@@ -351,27 +368,14 @@ But... as with most things written in Ruby, it's all more about *productivity* t
|
|
351
368
|
|
352
369
|
Take the best ideas from these and incorporate:
|
353
370
|
* /usr/lib/ruby/gems/1.8/gems/rscm-0.5.1/lib/rscm/scm/subversion.rb
|
354
|
-
* /usr/lib/ruby/gems/1.8/gems/rscm-0.5.1/lib/rscm/scm/subversion_log_parser.rb
|
355
371
|
* /usr/lib/ruby/gems/1.8/gems/lazysvn-0.1.3/lib/subversion.rb
|
356
372
|
|
357
373
|
Possibly switch to LazySvn.
|
358
374
|
|
359
375
|
After you save/edit/set an svn:externals, it should try to automatically pretty up the margins/alignment for you.
|
360
376
|
|
361
|
-
Color menu_item for do you want to edit this external yes/no
|
362
|
-
|
363
|
-
====================================================================================================
|
364
|
-
Diff of externals (**don't forget to commit these too!**):
|
365
|
-
----------------------------------------------------------------------------------------------------
|
366
|
-
to use ANSI underlines/colors
|
367
|
-
|
368
377
|
Done, I think:
|
369
378
|
Make sure to show errors!
|
370
|
-
~/svn st * wasn't showing an error it should have been
|
371
|
-
> /usr/bin/svn status change_all_externals.rb change_all_externals.sh devscripts frontend glass glass.net potluck shared
|
372
|
-
svn: 'change_all_externals.rb' is not a working copy
|
373
|
-
|
374
|
-
If wrapped svn ever exits with an error code (such as 1), we ought to throw a fit as well
|
375
379
|
|
376
380
|
If there is an error during an update, such as this one:
|
377
381
|
Fetching external item into 'glass/rails_backend/vendor/plugins/our_extensions'
|
@@ -10,6 +10,7 @@ gem 'facets', '>=1.8.51'
|
|
10
10
|
require 'facets/core/kernel/require_local'
|
11
11
|
require 'facets/core/enumerable/uniq_by'
|
12
12
|
require 'facets/core/kernel/silence_stream'
|
13
|
+
require 'facets/core/module/initializer'
|
13
14
|
|
14
15
|
gem 'qualitysmith_extensions', '>=0.0.7'
|
15
16
|
|
@@ -20,6 +21,7 @@ gem 'qualitysmith_extensions', '>=0.0.7'
|
|
20
21
|
#require 'facets/core/class/cattr'
|
21
22
|
gem 'qualitysmith_extensions'
|
22
23
|
require 'qualitysmith_extensions/module/attribute_accessors'
|
24
|
+
require 'qualitysmith_extensions/module/guard_method'
|
23
25
|
|
24
26
|
# RSCM is used for some of the abstraction, such as for parsing log messages into nice data structures. It seems like overkill, though, to use RSCM for most things...
|
25
27
|
gem 'rscm'
|
@@ -32,6 +34,7 @@ module Subversion
|
|
32
34
|
# True if you want output from svn to be colorized (useful if output is for human eyes, but not useful if using the output programatically)
|
33
35
|
@@color = false
|
34
36
|
mattr_accessor :color
|
37
|
+
mguard_method :with_color!, :@@color
|
35
38
|
|
36
39
|
# If true, will only output which command _would_ have been executed but will not actually execute it.
|
37
40
|
@@dry_run = false
|
@@ -78,6 +81,10 @@ module Subversion
|
|
78
81
|
add_to_property 'externals', options[:local_path], "#{options[:as]} #{repo_url}"
|
79
82
|
end
|
80
83
|
|
84
|
+
def self.export(path_or_url, target)
|
85
|
+
execute "export #{path_or_url} #{target}"
|
86
|
+
end
|
87
|
+
|
81
88
|
# Removes the given items from the repository and the disk. Items may contain wildcards.
|
82
89
|
def self.remove(*args)
|
83
90
|
execute "rm #{args.join ' '}"
|
@@ -143,6 +150,11 @@ module Subversion
|
|
143
150
|
execute("update #{args.join ' '}")
|
144
151
|
end
|
145
152
|
|
153
|
+
def self.commit(*args)
|
154
|
+
args = ['./'] if args.empty?
|
155
|
+
execute("commit #{args.join ' '}")
|
156
|
+
end
|
157
|
+
|
146
158
|
# The output from `svn status` is nicely divided into two "sections": the section which pertains to the current working copy (not
|
147
159
|
# counting externals as part of the working copy) and then the section with status of all of the externals.
|
148
160
|
# This method returns the first section.
|
@@ -180,11 +192,19 @@ module Subversion
|
|
180
192
|
}
|
181
193
|
end
|
182
194
|
|
183
|
-
# Returns the
|
195
|
+
# Returns the modifications to the working directory or URL specified in +args+.
|
184
196
|
def self.diff(*args)
|
185
197
|
args = ['./'] if args.empty?
|
186
|
-
|
187
|
-
|
198
|
+
execute("diff #{"--diff-cmd colordiff" if color?} #{args.join ' '}")
|
199
|
+
end
|
200
|
+
# Parses the output from diff and returns an array of Diff objects.
|
201
|
+
def self.diffs(*args)
|
202
|
+
args = ['./'] if args.empty?
|
203
|
+
raw_diffs = nil
|
204
|
+
with_color! false do
|
205
|
+
raw_diffs = diff(*args)
|
206
|
+
end
|
207
|
+
DiffsParser.new(raw_diffs).parse
|
188
208
|
end
|
189
209
|
|
190
210
|
# It's easy to get/set properties, but less easy to add to a property. This method uses get/set to simulate add.
|
@@ -264,9 +284,16 @@ module Subversion
|
|
264
284
|
# Returns the revision number for head.
|
265
285
|
def self.latest_revision(*args)
|
266
286
|
args = ['./'] if args.empty?
|
287
|
+
# The revision returned by svn status -u seems to be a pretty reliable way to get this. Does anyone know of a better way?
|
267
288
|
matches = /Status against revision:\s+(\d+)/m.match(status_against_server(args))
|
268
289
|
matches && matches[1]
|
269
290
|
end
|
291
|
+
# Returns the revision number for the working directory(/file?) specified by +path+
|
292
|
+
def self.latest_revision_for_path(path)
|
293
|
+
# The revision returned by svn info seems to be a pretty reliable way to get this. Does anyone know of a better way?
|
294
|
+
matches = info(path).match(/^Revision: (\d+)/)
|
295
|
+
matches && matches[1]
|
296
|
+
end
|
270
297
|
|
271
298
|
# Returns an array of RSCM::Revision objects
|
272
299
|
def self.revisions(*args)
|
@@ -287,10 +314,15 @@ module Subversion
|
|
287
314
|
execute "info #{args.join(' ')}"
|
288
315
|
end
|
289
316
|
|
317
|
+
def self.url(path_or_url = './')
|
318
|
+
matches = info(path_or_url).match(/^URL: (.+)/)
|
319
|
+
matches && matches[1]
|
320
|
+
end
|
321
|
+
|
290
322
|
# :todo: needs some serious unit-testing love
|
291
323
|
def self.base_url(path_or_url = './')
|
292
|
-
|
293
|
-
|
324
|
+
matches = info(path_or_url).match(/^Repository Root: (.+)/)
|
325
|
+
matches && matches[1]
|
294
326
|
|
295
327
|
# It appears that we might need to use this old way (which looks at 'URL'), since there is actually a
|
296
328
|
# base_url = nil # needed so that base_url variable isn't local to loop block (and reset during next iteration)!
|
@@ -407,10 +439,8 @@ end
|
|
407
439
|
|
408
440
|
|
409
441
|
|
410
|
-
|
411
|
-
|
442
|
+
#-----------------------------------------------------------------------------------------------------------------------------
|
412
443
|
module Subversion
|
413
|
-
|
414
444
|
RevisionProperty = Struct.new(:name, :value)
|
415
445
|
|
416
446
|
# Represents an "externals container", which is a directory that has the <tt>svn:externals</tt> property set to something useful.
|
@@ -458,6 +488,62 @@ module Subversion
|
|
458
488
|
self.container_dir == other.container_dir
|
459
489
|
end
|
460
490
|
end
|
461
|
-
end
|
462
491
|
|
492
|
+
# A collection of Diff objects in in file_name => diff format.
|
493
|
+
class Diffs < Hash
|
494
|
+
end
|
495
|
+
|
496
|
+
class Diff
|
497
|
+
attr_reader :filename, :diff
|
498
|
+
initializer :filename do
|
499
|
+
@diff = ''
|
500
|
+
end
|
501
|
+
def filename_pretty
|
502
|
+
filename.ljust(100).black_on_white
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
class DiffsParser
|
507
|
+
class ParseError < Exception; end
|
508
|
+
initializer :raw_diffs
|
509
|
+
@state = nil
|
510
|
+
def parse
|
511
|
+
diffs = Diffs.new
|
512
|
+
current_diff = nil
|
513
|
+
@raw_diffs.each_line do |line|
|
514
|
+
if line =~ /^Index: (.*)$/
|
515
|
+
current_diff = Diff.new($1)
|
516
|
+
diffs[current_diff.filename] = current_diff #unless current_diff.nil?
|
517
|
+
@state = :immediately_after_filename
|
518
|
+
next
|
519
|
+
end
|
520
|
+
|
521
|
+
if current_diff.nil?
|
522
|
+
raise ParseError.new("The raw diff input didn't begin with 'Index:'!")
|
523
|
+
end
|
524
|
+
|
525
|
+
if @state == :immediately_after_filename
|
526
|
+
if line =~ /^===================================================================$/ ||
|
527
|
+
line =~ /^---.*\(revision \d+\)$/ ||
|
528
|
+
line =~ /^\+\+\+.*\(revision \d+\)$/ ||
|
529
|
+
line =~ /^@@ .* @@$/
|
530
|
+
# Skip
|
531
|
+
next
|
532
|
+
else
|
533
|
+
@state= :inside_the_actual_diff
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
if @state == :inside_the_actual_diff
|
538
|
+
current_diff.diff << line
|
539
|
+
else
|
540
|
+
raise ParseError.new("Expected to be in :inside_the_actual_diff state, but was not.")
|
541
|
+
end
|
542
|
+
end
|
543
|
+
diffs.freeze
|
544
|
+
diffs
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
end
|
463
549
|
end
|
@@ -8,6 +8,8 @@ require 'facets/core/array/select' # select!
|
|
8
8
|
require 'facets/core/kernel/with' # returning
|
9
9
|
require 'facets/core/string/lines'
|
10
10
|
require 'facets/core/string/index_all'
|
11
|
+
require 'facets/core/string/to_re'
|
12
|
+
require 'facets/core/string/to_rx'
|
11
13
|
|
12
14
|
gem 'qualitysmith_extensions', '>=0.0.3'
|
13
15
|
require 'qualitysmith_extensions/enumerable/enum'
|
@@ -61,6 +63,19 @@ class String
|
|
61
63
|
def relativize_path
|
62
64
|
self.gsub(File.expand_path(FileUtils.getwd) + '/', '') # Simplify the directory by removing the working directory from it, if possible
|
63
65
|
end
|
66
|
+
def highlight_occurences(search_pattern, color = :red)
|
67
|
+
self.gsub(search_pattern) { $&.send(color).bold }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
def confirm(question, options = ['Yes', 'No'])
|
71
|
+
print question + " " +
|
72
|
+
"Yes".menu_item(:red) + ", " +
|
73
|
+
"No".menu_item(:green) +
|
74
|
+
" > "
|
75
|
+
response = ''
|
76
|
+
# Currently allow user to press Enter to accept the default.
|
77
|
+
response = $stdin.getc.chr.downcase while !['y', 'n', "\n"].include?(begin response.downcase!; response end)
|
78
|
+
response
|
64
79
|
end
|
65
80
|
|
66
81
|
Subversion.extend(Subversion::Extensions)
|
@@ -234,19 +249,24 @@ module Subversion
|
|
234
249
|
alias_method :__knowingly_committing_broken_code, :__broken
|
235
250
|
end
|
236
251
|
def commit(*args)
|
252
|
+
latest_rev_before_commit = Subversion.latest_revision if @broken || @skip_notification
|
253
|
+
|
237
254
|
Subversion.print_commands_for do
|
238
|
-
puts svn(:capture, "propset svn:skip_commit_notification_for_next_commit true --revprop -r #{
|
255
|
+
puts svn(:capture, "propset svn:skip_commit_notification_for_next_commit true --revprop -r #{latest_rev_before_commit}", :prepare_args => false)
|
239
256
|
end if @skip_notification
|
240
257
|
# :todo:
|
241
258
|
# Add some logic to automatically skip the commit e-mail if the size of the files to be committed exceeds a threshold of __ MB.
|
242
259
|
# (Performance idea: Only check the size of the files if svn st includes (bin)?)
|
243
260
|
|
244
|
-
|
261
|
+
svn(:system, 'commit', *(['--force-log'] + args))
|
245
262
|
|
246
|
-
|
263
|
+
# The following only works if we do :capture (`svn`), but that doesn't work so well (at all) if svn tries to open up an editor (vim),
|
264
|
+
# which is what happens if you don't specify a message.:
|
265
|
+
# puts output = svn(:capture, 'commit', *(['--force-log'] + args))
|
266
|
+
# just_committed = (matches = output.match(/Committed revision (\d+)\./)) && matches[1]
|
247
267
|
|
248
268
|
Subversion.print_commands_for do
|
249
|
-
puts svn(:capture, "propset code:broken true --revprop -r #{
|
269
|
+
puts svn(:capture, "propset code:broken true --revprop -r #{latest_rev_before_commit + 1}", :prepare_args => false)
|
250
270
|
end if @broken
|
251
271
|
|
252
272
|
end
|
@@ -255,6 +275,50 @@ module Subversion
|
|
255
275
|
# * look for .svn-commit files within current tree and if one is found, show what's in it and ask
|
256
276
|
# "Found a commit message from a previous failed commit. {preview} Do you want to (u)se this message for the current commit, or (d)elete it?"
|
257
277
|
|
278
|
+
# A fix for this annoying problem that I seem to come across all too frequentrly:
|
279
|
+
# svn: Commit failed (details follow):
|
280
|
+
# svn: Your file or directory 'whatever.rb' is probably out-of-date
|
281
|
+
def fix_out_of_date_commit_state(dir)
|
282
|
+
dir = $1 if dir =~ %r|^(.*)/$| # Strip trailing slash.
|
283
|
+
|
284
|
+
puts Subversion.export("#{dir}", "#{dir}.new"). # Exports (copies) the contents of working copy 'dir' (including your uncommitted changes, don't worry! ... and you'll get a chance to confirm before anything is deleted; but sometimes although it exports files that are scheduled for addition, they are no longer scheduled for addition in the new working copy, so you have to re-add them) to non-working-copy 'dir.new'
|
285
|
+
add_exit_code_error
|
286
|
+
return if !$?.success?
|
287
|
+
|
288
|
+
system("mv #{dir} #{dir}.backup") # Just in case something goes ary
|
289
|
+
puts ''.add_exit_code_error
|
290
|
+
return if !$?.success?
|
291
|
+
|
292
|
+
puts "Restoring #{dir}..."
|
293
|
+
Subversion.update dir # Restore the directory to a pristine state so we will no longer get that annoying error
|
294
|
+
|
295
|
+
# Assure the user that dir.new really does have your latest changes
|
296
|
+
#puts "Here's a diff. Your changes/additions will be in the *right* (>) file."
|
297
|
+
#system("diff #{dir}.backup #{dir}")
|
298
|
+
|
299
|
+
# Merge those latest changes back into the pristine working copy
|
300
|
+
system("cp -R #{dir}.new/. #{dir}/")
|
301
|
+
|
302
|
+
# Assure the user one more time
|
303
|
+
puts Extensions.diff(dir)
|
304
|
+
|
305
|
+
# Actually commit
|
306
|
+
puts
|
307
|
+
response = confirm("Are you ready to try the commit again now?")
|
308
|
+
puts
|
309
|
+
if response == 'y'
|
310
|
+
puts "Great. Go for it."
|
311
|
+
#Subversion.commit dir
|
312
|
+
end
|
313
|
+
|
314
|
+
# Clean up
|
315
|
+
#puts
|
316
|
+
#response = confirm("Do you want to delete array.backup array.new now?")
|
317
|
+
puts "Don't forget to delete array.backup array.new now!"
|
318
|
+
#rm_rf array.backup, array.new
|
319
|
+
puts
|
320
|
+
end
|
321
|
+
|
258
322
|
#-----------------------------------------------------------------------------------------------------------------------------
|
259
323
|
module Diff
|
260
324
|
Console::Command.pass_through({
|
@@ -287,7 +351,7 @@ module Subversion
|
|
287
351
|
unless diff_output == ""
|
288
352
|
#output.puts '-'*100
|
289
353
|
#output.puts item.ljust(100, ' ').black_on_white.bold.underline
|
290
|
-
output.puts item.black_on_white.bold
|
354
|
+
output.puts item.ljust(100).black_on_white.bold
|
291
355
|
output.puts diff_output
|
292
356
|
end
|
293
357
|
end
|
@@ -449,6 +513,11 @@ End
|
|
449
513
|
# Custom subcommands
|
450
514
|
#-----------------------------------------------------------------------------------------------------------------------------
|
451
515
|
|
516
|
+
#-----------------------------------------------------------------------------------------------------------------------------
|
517
|
+
def url(*args)
|
518
|
+
puts Subversion.url(*args)
|
519
|
+
end
|
520
|
+
|
452
521
|
#-----------------------------------------------------------------------------------------------------------------------------
|
453
522
|
def repository_root(*args)
|
454
523
|
puts Subversion.repository_root(*args)
|
@@ -574,15 +643,12 @@ End
|
|
574
643
|
|
575
644
|
response = ""
|
576
645
|
if File.directory?(file)
|
577
|
-
|
578
|
-
"Yes".menu_item(:red) + ", " +
|
579
|
-
"No".menu_item(:green) +
|
580
|
-
" > "
|
581
|
-
response = $stdin.getc.chr.downcase while !['y', 'n', "\n"].include?(begin response.downcase!; response end)
|
646
|
+
response = confirm("Are you pretty much " + "SURE".bold + " you want to '" + "rm -rf #{file}".red.bold + "'? ")
|
582
647
|
else
|
583
648
|
response = "y"
|
584
649
|
end
|
585
650
|
|
651
|
+
puts "response=#{response}"
|
586
652
|
if response == 'y'
|
587
653
|
print "\nDeleting... "
|
588
654
|
FileUtils.rm_rf file
|
@@ -697,9 +763,7 @@ End
|
|
697
763
|
command = "#{Subversion.executable} propedit svn:externals #{external.container_dir}"
|
698
764
|
#puts command
|
699
765
|
begin
|
700
|
-
|
701
|
-
print "Do you want to edit svn:externals for this directory?".black_on_white + ' ' + 'yes'.menu_item(:white) + '/' + 'No'.menu_item(:white) + " > "
|
702
|
-
response = $stdin.getc.chr.downcase
|
766
|
+
response = confirm("Do you want to edit svn:externals for this directory?".black_on_white)
|
703
767
|
system command if response == 'y'
|
704
768
|
rescue Interrupt
|
705
769
|
puts "\nGoodbye!"
|
@@ -816,12 +880,7 @@ End
|
|
816
880
|
# we can use the empty string as a way to trigger a propdel...
|
817
881
|
if value == ''
|
818
882
|
puts
|
819
|
-
|
820
|
-
"Yes".menu_item(:red) + ", " +
|
821
|
-
"No".menu_item(:green) +
|
822
|
-
" > "
|
823
|
-
response = ''
|
824
|
-
response = $stdin.getc.chr.downcase while !['y', 'n', "\n"].include?(begin response.downcase!; response end)
|
883
|
+
response = confirm("Are you sure you want to delete property #{property_name}".red.bold + "'? ")
|
825
884
|
puts
|
826
885
|
if response == 'y'
|
827
886
|
Subversion.print_commands_for do
|
@@ -880,14 +939,32 @@ End
|
|
880
939
|
# Only show revisions that are in need of a code review
|
881
940
|
# :todo:
|
882
941
|
def __unreviewed_only
|
883
|
-
@unreviewed_only
|
942
|
+
@unreviewed_only = true
|
943
|
+
end
|
944
|
+
|
945
|
+
# Only show revisions that were committed by a certain author.
|
946
|
+
# :todo:
|
947
|
+
def __by(author)
|
948
|
+
@author_filter = author
|
949
|
+
end
|
950
|
+
def __author(author)
|
951
|
+
@author_filter = author
|
884
952
|
end
|
885
953
|
end
|
886
|
-
# :todo: document in readme! test! release! annouce!
|
887
954
|
def revisions(directory = './')
|
888
955
|
puts "Getting list of revisions for '#{directory.white.bold}' ..."
|
889
956
|
|
890
957
|
head = Subversion.latest_revision
|
958
|
+
revision_of_directory = Subversion.latest_revision_for_path(directory)
|
959
|
+
|
960
|
+
# It's possible for a working copy to get "out of date" (even if you were the last committer!), in which case svn log will
|
961
|
+
# only list revisions up to that revision (actually looks like it only goes up to and including Last Changed Rev: 2838,
|
962
|
+
# not Revision: 2839, as reported by svn info...)
|
963
|
+
if revision_of_directory < head
|
964
|
+
puts "The working copy '#{directory.white.bold}' appears to be out-of-date (#{revision_of_directory}) with respect to the head revision (#{head}). Updating..."
|
965
|
+
Subversion.update(directory)
|
966
|
+
end
|
967
|
+
|
891
968
|
revisions = Subversion.revisions(directory)
|
892
969
|
|
893
970
|
puts "#{revisions.length.to_s.bold} revisions found. Starting with #{@reverse ? 'oldest' : 'most recent'} revision and #{@reverse ? 'going forward in time' : 'going backward in time'}..."
|
@@ -969,12 +1046,32 @@ End
|
|
969
1046
|
SvnCommand.execute("diff #{directory} --ignore-externals -r #{revs_to_compare.min}:#{revs_to_compare.max}")
|
970
1047
|
|
971
1048
|
when 'g' # Grep the changeset
|
1049
|
+
# :todo; make it accept regexpes like /like.*this/im so you can make it case insensitive or multi-line
|
972
1050
|
revs_to_compare = [other_rev, rev]
|
973
1051
|
puts
|
1052
|
+
print 'Grep for'.bold + ' (Regular expressions ' + 'like.*this'.bold.blue + ' are allowed, but not ' + '/like.*this/im'.bold.blue + '): '
|
1053
|
+
search_pattern = $stdin.gets.chomp.to_rx
|
974
1054
|
puts((' '*100).green.underline)
|
975
|
-
|
976
|
-
|
977
|
-
|
1055
|
+
puts "Searching `svn diff #{revs_to_compare.min}:#{revs_to_compare.max}` for #{search_pattern.to_s}... ".bold
|
1056
|
+
diffs = Subversion.diffs(directory, '-r', "#{revs_to_compare.min}:#{revs_to_compare.max}")
|
1057
|
+
|
1058
|
+
hits = 0
|
1059
|
+
diffs.each do |filename, diff|
|
1060
|
+
#.grep(search_pattern)
|
1061
|
+
if diff.diff =~ search_pattern
|
1062
|
+
puts diff.filename_pretty
|
1063
|
+
puts( diff.diff.grep(search_pattern). # This will get us just the interesting *lines* (as an array).
|
1064
|
+
map { |line| # Now, for each line...
|
1065
|
+
hits += 1
|
1066
|
+
line.highlight_occurences(search_pattern)
|
1067
|
+
}
|
1068
|
+
)
|
1069
|
+
end
|
1070
|
+
end
|
1071
|
+
if hits == 0
|
1072
|
+
puts "Search term not found!".red.bold
|
1073
|
+
end
|
1074
|
+
show_revision_again = false
|
978
1075
|
|
979
1076
|
when 'l' # List revision properties
|
980
1077
|
puts
|
@@ -997,6 +1094,14 @@ End
|
|
997
1094
|
|
998
1095
|
show_revision_again = false
|
999
1096
|
|
1097
|
+
when 'c' # Cat all files from revision
|
1098
|
+
puts 'Not implemented yet'
|
1099
|
+
show_revision_again = false
|
1100
|
+
|
1101
|
+
when 'a' # Grep the cat
|
1102
|
+
puts 'Not implemented yet'
|
1103
|
+
show_revision_again = false
|
1104
|
+
|
1000
1105
|
when 'r' # Mark as reviewed
|
1001
1106
|
puts
|
1002
1107
|
your_name = ENV['USER'] # I would use the same username that Subversion itself would use if you committed
|
data/test/subversion_test.rb
CHANGED
@@ -75,69 +75,56 @@ class SubversionTest < Test::Unit::TestCase
|
|
75
75
|
FileUtils.rm_r tmpdir
|
76
76
|
end
|
77
77
|
end
|
78
|
+
end
|
78
79
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
def
|
85
|
-
Subversion
|
86
|
-
assert_equal "svn propset svn:executable '' foo", Subversion.executed[0]
|
87
|
-
assert_equal "svn propset svn:executable '' bar", Subversion.executed[1]
|
88
|
-
assert_equal "svn propset svn:executable '' hello/world", Subversion.executed[2]
|
89
|
-
|
90
|
-
Subversion.make_not_executable 'foo'
|
91
|
-
assert_equal "svn propdel svn:executable foo", Subversion.executed[3]
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_status
|
95
|
-
Subversion.status 'foo'
|
96
|
-
assert_equal "svn status foo", Subversion.executed.first
|
80
|
+
class DiffsParserTest < Test::Unit::TestCase
|
81
|
+
# def test_diff_class_acts_like_hash
|
82
|
+
# diff = Subversion::Diff['file.rb' => "some differences"]
|
83
|
+
# assert_equal 'some differences', diff['file.rb']
|
84
|
+
# end
|
85
|
+
def test_parser_error
|
86
|
+
assert_raise(Subversion::DiffsParser::ParseError) { Subversion::DiffsParser.new('what').parse }
|
97
87
|
end
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
88
|
+
def test_parser
|
89
|
+
diffs = Subversion::DiffsParser.new(<<End).parse
|
90
|
+
Index: lib/test_extensions.rb
|
91
|
+
===================================================================
|
92
|
+
--- lib/test_extensions.rb (revision 2871)
|
93
|
+
+++ lib/test_extensions.rb (revision 2872)
|
94
|
+
@@ -6,6 +6,7 @@
|
95
|
+
require_local 'some_file'
|
96
|
+
|
97
|
+
gem 'qualitysmith_extensions'
|
98
|
+
+require 'qualitysmith_extensions/regexp/join'
|
99
|
+
require 'qualitysmith_extensions/kernel/capture_output.rb'
|
100
|
+
require 'qualitysmith_extensions/kernel/simulate_input.rb'
|
101
|
+
|
102
|
+
Index: Readme
|
103
|
+
===================================================================
|
104
|
+
--- Readme (revision 0)
|
105
|
+
+++ Readme (revision 2872)
|
106
|
+
@@ -0,0 +1,2 @@
|
107
|
+
+* Blah blah blah
|
108
|
+
+* Blah blah blah
|
109
109
|
End
|
110
|
-
assert_equal
|
111
|
-
|
112
|
-
assert_equal
|
113
|
-
assert_equal
|
114
|
-
assert_equal '
|
115
|
-
|
116
|
-
|
117
|
-
|
110
|
+
assert_equal Subversion::Diffs, diffs.class
|
111
|
+
assert diffs.frozen?
|
112
|
+
assert_equal 2, diffs.keys.size
|
113
|
+
assert_equal 2, diffs.values.size
|
114
|
+
assert_equal <<End, diffs['lib/test_extensions.rb'].diff
|
115
|
+
require_local 'some_file'
|
116
|
+
|
117
|
+
gem 'qualitysmith_extensions'
|
118
|
+
+require 'qualitysmith_extensions/regexp/join'
|
119
|
+
require 'qualitysmith_extensions/kernel/capture_output.rb'
|
120
|
+
require 'qualitysmith_extensions/kernel/simulate_input.rb'
|
118
121
|
|
119
|
-
def test_revision_properties_names
|
120
|
-
Subversion.stubs(:proplist).returns(<<End)
|
121
|
-
Unversioned properties on revision 2819:
|
122
|
-
svn:log
|
123
|
-
svn:author
|
124
|
-
svn:date
|
125
122
|
End
|
126
|
-
assert_equal
|
127
|
-
|
128
|
-
|
129
|
-
Subversion.stubs(:proplist).returns(<<End)
|
130
|
-
Unversioned properties on revision 2819:
|
131
|
-
svn:log
|
132
|
-
svn:author
|
133
|
-
svn:date
|
123
|
+
assert_equal <<End, diffs['Readme'].diff
|
124
|
+
+* Blah blah blah
|
125
|
+
+* Blah blah blah
|
134
126
|
End
|
135
|
-
Subversion.stubs(:get_revision_property).returns('a value')
|
136
127
|
|
137
|
-
assert_equal [
|
138
|
-
Subversion::RevisionProperty.new('svn:log', 'a value'),
|
139
|
-
Subversion::RevisionProperty.new('svn:author', 'a value'),
|
140
|
-
Subversion::RevisionProperty.new('svn:date', 'a value'),
|
141
|
-
], Subversion.revision_properties(rev = 14)
|
142
128
|
end
|
129
|
+
|
143
130
|
end
|
data/test/svn_command_test.rb
CHANGED
@@ -3,64 +3,15 @@ require File.dirname(__FILE__) + '/test_helper'
|
|
3
3
|
require_local '../lib/svn-command/svn_command.rb'
|
4
4
|
require 'facets/core/string/to_re'
|
5
5
|
require 'yaml'
|
6
|
-
|
7
|
-
|
8
6
|
require 'facets/core/module/alias_method_chain'
|
9
|
-
require 'qualitysmith_extensions/
|
10
|
-
|
11
|
-
module Unit
|
12
|
-
module Assertions
|
13
|
-
# Rather than showing the expected and the actual and asking the user to figure out the commonalities and differences
|
14
|
-
# himself, this method will highlight the differences for the user (in color), so that they can be spotted in less than
|
15
|
-
# an instant!
|
16
|
-
# Strings: show common characters in a plain color and highlight the characters that differ (at that index) in yellow.
|
17
|
-
# Strings: show common elements in a plain color and highlight the elements that differ (at that index) in yellow.
|
18
|
-
def assert_equal_with_difference_highlighting(expected, actual, message=nil)
|
19
|
-
String.class_eval do
|
20
|
-
alias_method :colorize, :colorize_without_no_color
|
21
|
-
end
|
22
|
-
if String===expected && String===actual
|
23
|
-
expected_with_highlighting = ''
|
24
|
-
actual_with_highlighting = ''
|
25
|
-
expected.each_char_with_index do |i, c|
|
26
|
-
if c != actual[i].chr
|
27
|
-
expected_with_highlighting << c.yellow
|
28
|
-
actual_with_highlighting << actual[i].chr.yellow
|
29
|
-
else
|
30
|
-
expected_with_highlighting << c
|
31
|
-
actual_with_highlighting << c
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
full_message = build_message(message, <<End, expected_with_highlighting, actual_with_highlighting)
|
36
|
-
<?>
|
37
|
-
expected but was
|
38
|
-
<?>.
|
39
|
-
End
|
40
|
-
puts actual_with_highlighting if expected != actual
|
41
|
-
assert_block(full_message) { expected == actual }
|
42
|
-
else
|
43
|
-
assert_equal_without_difference_highlighting(expected, actual, message)
|
44
|
-
end
|
45
|
-
String.class_eval do
|
46
|
-
alias_method :colorize, :colorize_with_no_color
|
47
|
-
end
|
48
|
-
end # def assert_equal_with_difference_highlighting
|
7
|
+
require 'qualitysmith_extensions/colored/toggleability'
|
8
|
+
require 'qualitysmith_extensions/regexp/join'
|
49
9
|
|
50
|
-
alias_method_chain :assert_equal, :difference_highlighting
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
10
|
|
55
11
|
|
56
|
-
Subversion.color = false
|
57
12
|
# Makes testing simpler. We can test all the *colorization* features via *manual* testing (since they're not as critical).
|
58
|
-
|
59
|
-
|
60
|
-
string
|
61
|
-
end
|
62
|
-
alias_method_chain :colorize, :no_color
|
63
|
-
end
|
13
|
+
Subversion.color = false
|
14
|
+
String.color_on! false
|
64
15
|
|
65
16
|
module Subversion
|
66
17
|
class BaseSvnCommandTest < Test::Unit::TestCase
|
@@ -147,11 +98,11 @@ end
|
|
147
98
|
class SvnCommitTest < BaseSvnCommandTest
|
148
99
|
def test_1
|
149
100
|
SvnCommand.execute("commit -m 'just an ordinary commit message!'")
|
150
|
-
assert_equal "svn commit -m 'just an ordinary commit message!' --force-log", Subversion.executed
|
101
|
+
assert_equal ["svn commit -m 'just an ordinary commit message!' --force-log"], Subversion.executed
|
151
102
|
end
|
152
103
|
def test_lots_of_options
|
153
104
|
SvnCommand.execute("commit --non-recursive -q -m '' --targets some_file ")
|
154
|
-
assert_equal "svn commit --non-recursive -q -m '' --targets some_file --force-log", Subversion.executed
|
105
|
+
assert_equal ["svn commit --non-recursive -q -m '' --targets some_file --force-log"], Subversion.executed
|
155
106
|
end
|
156
107
|
def test_that_complex_quoting_doesnt_confuse_it
|
157
108
|
original_message = "Can't decide how many \"'quotes'\" to use!"
|
@@ -565,7 +516,7 @@ end
|
|
565
516
|
# Changeset/commit/log Browser
|
566
517
|
|
567
518
|
class SvnRevisionsTest < BaseSvnCommandTest
|
568
|
-
def
|
519
|
+
def set_up_stubs
|
569
520
|
Subversion.stubs(:revisions).returns(
|
570
521
|
begin
|
571
522
|
RSCM::Revisions.class_eval do
|
@@ -600,8 +551,14 @@ class SvnRevisionsTest < BaseSvnCommandTest
|
|
600
551
|
revisions.revisions = [revision1, revision2]
|
601
552
|
end
|
602
553
|
)
|
554
|
+
Subversion.stubs(:latest_revision).returns(42)
|
555
|
+
Subversion.stubs(:latest_revision_for_path).returns(42)
|
603
556
|
Subversion.stubs(:diff).returns("the diff")
|
604
|
-
|
557
|
+
end
|
558
|
+
|
559
|
+
def test_view_changeset
|
560
|
+
set_up_stubs
|
561
|
+
|
605
562
|
output = simulate_input(
|
606
563
|
'v' + # View this changeset
|
607
564
|
"\n" + # Continue to revision 1800
|
@@ -609,52 +566,51 @@ class SvnRevisionsTest < BaseSvnCommandTest
|
|
609
566
|
) do
|
610
567
|
capture_output { SvnCommand.execute('revisions') }
|
611
568
|
end
|
612
|
-
puts output
|
613
|
-
require 'unroller'
|
569
|
+
#puts output
|
570
|
+
#require 'unroller'
|
614
571
|
#Unroller::trace :exclude_classes => /PP|PrettyPrint/ do
|
615
572
|
|
616
|
-
|
617
|
-
Getting list of revisions for './' ...
|
618
|
-
2 revisions found. Starting with most recent revision and going backward in time...
|
619
|
-
|
620
|
-
2. r1800 | tyler | 2007-12-01 00:00:00
|
573
|
+
assert_match Regexp.loose_join(
|
574
|
+
"Getting list of revisions for './' ...
|
575
|
+
2 revisions found. Starting with most recent revision and going backward in time...",
|
576
|
+
# Show 1800 again
|
577
|
+
"2. r1800 | tyler | 2007-12-01 00:00:00
|
621
578
|
I say! Quite the storm, what!
|
622
579
|
|
623
580
|
A dir/file1
|
624
581
|
M dir/file2
|
625
|
-
View this changeset, Diff against specific revision, Grep the changeset, List or Edit revision properties, svn Cat all files from revision, grep the cat,
|
626
|
-
mark as Reviewed, edit log Message, or browse using Up/Down/Enter keys >
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
Diffing 1799:1800...
|
638
|
-
the diff
|
639
|
-
|
640
|
-
2. r1800 | tyler | 2007-12-01 00:00:00
|
582
|
+
View this changeset, Diff against specific revision, Grep the changeset, List or Edit revision properties, svn Cat all files from revision, grep the cat,
|
583
|
+
mark as Reviewed, edit log Message, or browse using Up/Down/Enter keys >",
|
584
|
+
# Show the diff
|
585
|
+
"Diffing 1799:1800...",
|
586
|
+
"the diff",
|
587
|
+
# Show 1800 again
|
588
|
+
"2. r1800 | tyler | 2007-12-01 00:00:00
|
641
589
|
I say! Quite the storm, what!
|
642
590
|
|
643
591
|
A dir/file1
|
644
592
|
M dir/file2
|
645
|
-
View this changeset, Diff against specific revision, Grep the changeset, List or Edit revision properties, svn Cat all files from revision, grep the cat,
|
646
|
-
mark as Reviewed, edit log Message, or browse using Up/Down/Enter keys > Next...
|
647
|
-
|
648
|
-
1. r1801 | tyler | 2007-12-02 00:00:00
|
593
|
+
View this changeset, Diff against specific revision, Grep the changeset, List or Edit revision properties, svn Cat all files from revision, grep the cat,
|
594
|
+
mark as Reviewed, edit log Message, or browse using Up/Down/Enter keys > Next...",
|
595
|
+
# Now show 1801
|
596
|
+
"1. r1801 | tyler | 2007-12-02 00:00:00
|
649
597
|
These Romans are crazy!
|
650
598
|
|
651
599
|
M dir/file2
|
652
|
-
View this changeset, Diff against specific revision, Grep the changeset, List or Edit revision properties, svn Cat all files from revision, grep the cat,
|
653
|
-
mark as Reviewed, edit log Message, or browse using Up/Down/Enter keys > Next...
|
654
|
-
|
655
|
-
|
600
|
+
View this changeset, Diff against specific revision, Grep the changeset, List or Edit revision properties, svn Cat all files from revision, grep the cat,
|
601
|
+
mark as Reviewed, edit log Message, or browse using Up/Down/Enter keys > Next...",
|
602
|
+
:multi_line => true
|
603
|
+
), output
|
604
|
+
|
605
|
+
|
606
|
+
=begin
|
607
|
+
/.*/
|
608
|
+
}.*
|
609
|
+
=end
|
610
|
+
|
611
|
+
|
656
612
|
assert_equal [
|
657
|
-
"svn status -u ./" # To find head
|
613
|
+
#"svn status -u ./" # To find head
|
658
614
|
], Subversion.executed
|
659
615
|
end
|
660
616
|
end
|
data/test/test_helper.rb
CHANGED
@@ -4,12 +4,10 @@ require 'facets/core/kernel/require_local'
|
|
4
4
|
require 'facets/core/kernel/load_local'
|
5
5
|
require 'stubba'
|
6
6
|
$LOAD_PATH << File.dirname(__FILE__) + "/../lib"
|
7
|
-
require_local "shared/test_helper"
|
8
7
|
|
9
|
-
gem '
|
10
|
-
require '
|
11
|
-
|
12
|
-
require 'qualitysmith_extensions/kernel/simulate_input.rb'
|
8
|
+
gem 'test_extensions'
|
9
|
+
require 'test_extensions'
|
10
|
+
gem 'qualitysmith_extensions'
|
13
11
|
|
14
12
|
require_local '../lib/svn-command/subversion'
|
15
13
|
if $mock_subversion
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: svn-command
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.2.5
|
7
|
+
date: 2007-05-01 00:00:00 -07:00
|
8
8
|
summary: A nifty wrapper command for Subversion's command-line svn client
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -41,8 +41,6 @@ files:
|
|
41
41
|
- test/subversion_extensions_test.rb
|
42
42
|
- test/subversion_test.rb
|
43
43
|
- test/svn_command_test.rb
|
44
|
-
- test/shared/test_helper.rb
|
45
|
-
- test/shared/test_helpers/test_colorizer.rb
|
46
44
|
- bin/rscm_test
|
47
45
|
- bin/command_completion_for_svn_command
|
48
46
|
- bin/svn
|
data/test/shared/test_helper.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
gem 'colored'
|
3
|
-
require 'test/unit'
|
4
|
-
require 'colored'
|
5
|
-
|
6
|
-
module Test::Unit
|
7
|
-
|
8
|
-
class Error
|
9
|
-
# the 'E' that is displayed as the tests are run
|
10
|
-
def single_character_display
|
11
|
-
"E".red.bold
|
12
|
-
end
|
13
|
-
|
14
|
-
# the long message that is displayed after test is run
|
15
|
-
def long_display
|
16
|
-
backtrace = filter_backtrace(@exception.backtrace).join("\n ")
|
17
|
-
[
|
18
|
-
"Error".red.bold,
|
19
|
-
":\n",
|
20
|
-
"#@test_name:".white,
|
21
|
-
"\n", "#{message}".red,
|
22
|
-
"\n #{backtrace}".gsub(/:(\d+):/,":#{'\1'.red}:")
|
23
|
-
].join('')
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
class Failure
|
29
|
-
# the 'E' that is displayed as the tests are run
|
30
|
-
def single_character_display
|
31
|
-
"F".yellow.bold
|
32
|
-
end
|
33
|
-
|
34
|
-
# the long message that is displayed after test is run
|
35
|
-
def long_display
|
36
|
-
location_display = if(location.size == 1)
|
37
|
-
location[0].sub(/\A(.+:\d+).*/, ' [\\1]')
|
38
|
-
else
|
39
|
-
"\n [#{location.join("\n ")}]"
|
40
|
-
end
|
41
|
-
[
|
42
|
-
"Failure".yellow.bold,
|
43
|
-
":\n","#@test_name".white,
|
44
|
-
"#{location_display}".gsub(/:(\d+)/, ":#{'\1'.yellow}"),
|
45
|
-
":\n", "#@message".yellow
|
46
|
-
].join('')
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# it is necessary to do a class_eval for the TestRunner class
|
51
|
-
# through the AutoRunner class, since the require in the AutoRunner
|
52
|
-
# class will overwrite what we do here otherwise.
|
53
|
-
#
|
54
|
-
# We must do the same thing inside of the TestRunner class
|
55
|
-
# class_eval for the TestResult class. We Modify the
|
56
|
-
# TestRunnerMediator class after the require is called,
|
57
|
-
# which will then modify the TestResult class.
|
58
|
-
#
|
59
|
-
# test_finished is the function that will output the
|
60
|
-
# '.' period during the test runs
|
61
|
-
#
|
62
|
-
# the to_s for TestResult class returns the string
|
63
|
-
# for the final tallied results
|
64
|
-
class AutoRunner
|
65
|
-
RUNNERS[:console] = proc do |r|
|
66
|
-
require 'test/unit/ui/console/testrunner'
|
67
|
-
Test::Unit::UI::Console::TestRunner.class_eval %q{
|
68
|
-
def test_finished(name)
|
69
|
-
output_single('.'.green, 1) unless (@already_outputted)
|
70
|
-
nl(3)
|
71
|
-
@already_outputted = false
|
72
|
-
end
|
73
|
-
|
74
|
-
def create_mediator(suite)
|
75
|
-
require 'test/unit/ui/testrunnermediator'
|
76
|
-
Test::Unit::UI::TestRunnerMediator.class_eval %q{
|
77
|
-
def create_result
|
78
|
-
Test::Unit::TestResult.class_eval %q{
|
79
|
-
def to_s
|
80
|
-
rc = [
|
81
|
-
"#{run_count}".white.bold,
|
82
|
-
"tests".white
|
83
|
-
].join(' ')
|
84
|
-
ac = [
|
85
|
-
"#{assertion_count}".white.bold,
|
86
|
-
"assertions".white
|
87
|
-
].join(' ')
|
88
|
-
fc = [
|
89
|
-
"#{failure_count}".yellow.bold,
|
90
|
-
"failures".yellow
|
91
|
-
].join(' ')
|
92
|
-
ec = [
|
93
|
-
"#{error_count}".red.bold,
|
94
|
-
"errors".red
|
95
|
-
].join(' ')
|
96
|
-
[rc, ac, fc, ec].join(', ')
|
97
|
-
end
|
98
|
-
}
|
99
|
-
TestResult.new
|
100
|
-
end
|
101
|
-
}
|
102
|
-
return Test::Unit::UI::TestRunnerMediator.new(suite)
|
103
|
-
end
|
104
|
-
}
|
105
|
-
Test::Unit::UI::Console::TestRunner
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|