perforce2svn 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/Gemfile.lock +38 -0
- data/LICENSE +23 -0
- data/README.markdown +66 -0
- data/Rakefile +24 -0
- data/bin/perforce2svn +11 -0
- data/lib/VERSION.yml +6 -0
- data/lib/perforce2svn/cli.rb +117 -0
- data/lib/perforce2svn/environment.rb +66 -0
- data/lib/perforce2svn/errors.rb +16 -0
- data/lib/perforce2svn/logging.rb +35 -0
- data/lib/perforce2svn/mapping/analyzer.rb +30 -0
- data/lib/perforce2svn/mapping/branch_mapping.rb +32 -0
- data/lib/perforce2svn/mapping/commands.rb +75 -0
- data/lib/perforce2svn/mapping/help.txt +139 -0
- data/lib/perforce2svn/mapping/lexer.rb +101 -0
- data/lib/perforce2svn/mapping/mapping_file.rb +65 -0
- data/lib/perforce2svn/mapping/operation.rb +8 -0
- data/lib/perforce2svn/mapping/parser.rb +145 -0
- data/lib/perforce2svn/migrator.rb +71 -0
- data/lib/perforce2svn/perforce/commit_builder.rb +159 -0
- data/lib/perforce2svn/perforce/p4_depot.rb +69 -0
- data/lib/perforce2svn/perforce/perforce_file.rb +81 -0
- data/lib/perforce2svn/subversion/svn_repo.rb +156 -0
- data/lib/perforce2svn/subversion/svn_transaction.rb +136 -0
- data/lib/perforce2svn/version_range.rb +43 -0
- data/mjt.map +7 -0
- data/perforce2svn.gemspec +49 -0
- data/spec/integration/hamlet.txt +7067 -0
- data/spec/integration/madmen_icon_bigger.jpg +0 -0
- data/spec/integration/perforce/p4_depot_spec.rb +16 -0
- data/spec/integration/perforce/perforce_file.yml +4 -0
- data/spec/integration/perforce/perforce_file_spec.rb +19 -0
- data/spec/integration/subversion/svn_repo_spec.rb +93 -0
- data/spec/integration/subversion/svn_transaction_spec.rb +112 -0
- data/spec/perforce2svn/cli_spec.rb +61 -0
- data/spec/perforce2svn/mapping/analyzer_spec.rb +41 -0
- data/spec/perforce2svn/mapping/branch_mapping_spec.rb +40 -0
- data/spec/perforce2svn/mapping/lexer_spec.rb +43 -0
- data/spec/perforce2svn/mapping/parser_spec.rb +140 -0
- data/spec/perforce2svn/perforce/commit_builder_spec.rb +74 -0
- data/spec/perforce2svn/version_range_spec.rb +42 -0
- data/spec/spec_helpers.rb +44 -0
- metadata +230 -0
Binary file
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helpers'
|
2
|
+
require 'perforce2svn/perforce/p4_depot'
|
3
|
+
|
4
|
+
module Perforce2Svn::Perforce
|
5
|
+
describe P4Depot do
|
6
|
+
it "should be able to connect to the Perforce server" do
|
7
|
+
attempting {
|
8
|
+
P4Depot.instance.connect!
|
9
|
+
}.should_not raise_error
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be able to retrieve the latest revision" do
|
13
|
+
P4Depot.instance.latest_revision.should >= 8000
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helpers'
|
2
|
+
require 'perforce2svn/perforce/perforce_file'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Perforce2Svn::Perforce
|
6
|
+
describe PerforceFile do
|
7
|
+
before :each do
|
8
|
+
config_file = File.join(File.dirname(__FILE__), 'perforce_file.yml')
|
9
|
+
@config = YAML::load_file(config_file)
|
10
|
+
@file = PerforceFile.new(@config['revision'], @config['path'], nil, 'text', 'add')
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be able to retrieve file contents." do
|
14
|
+
@file.contents.should match(Regexp.compile(@config['match']))
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should locate the symlink"
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'perforce2svn/errors'
|
2
|
+
require 'perforce2svn/subversion/svn_repo'
|
3
|
+
require 'spec_helpers'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module Perforce2Svn::Subversion
|
7
|
+
describe SvnRepo do
|
8
|
+
include CommitHelper
|
9
|
+
|
10
|
+
before :each do
|
11
|
+
@repo = SvnRepo.new('REPO')
|
12
|
+
end
|
13
|
+
|
14
|
+
after :each do
|
15
|
+
@repo.delete!
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should create a new repository upon initialization' do
|
19
|
+
File.exists?(@repo.repository_path).should be(true)
|
20
|
+
File.exists?(File.join(@repo.repository_path, 'hooks')).should be(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should fail to create a transaction when a block is not given' do
|
24
|
+
attempting {
|
25
|
+
@repo.transaction('me', Time.now, 'log')
|
26
|
+
}.should raise_error(Perforce2Svn::SvnTransactionError, /block-scoped/)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be able to retrieve the file contents from a path" do
|
30
|
+
write('/a', "this is some text")
|
31
|
+
@repo.pull_contents('/a').should eql("this is some text")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should fail when the file contents don't exist" do
|
35
|
+
attempting {
|
36
|
+
@repo.pull_contents('/a')
|
37
|
+
}.should raise_error(Svn::Error::FsNotFound, /revision 0/)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should fail when a file exists but not at a given revision" do
|
41
|
+
write('/a', 'content')
|
42
|
+
attempting {
|
43
|
+
@repo.pull_contents('/a', 10)
|
44
|
+
}.should raise_error(Svn::Error::FsNoSuchRevision, /10/)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be able to determine when a path doesn't exist" do
|
48
|
+
@repo.exists?('/a').should be_false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should be able to determine when a path exists" do
|
52
|
+
write('/a', 'contents')
|
53
|
+
@repo.exists?('/a').should be_true
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should be able to retrieve the commit log" do
|
57
|
+
write('/a', 'contents')
|
58
|
+
commit = @repo.commit_log(1)
|
59
|
+
commit.author.should eql('gabe')
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should be fail to retrieve the commit log on a bad revision" do
|
63
|
+
attempting {
|
64
|
+
@repo.commit_log(10)
|
65
|
+
}.should raise_error(Svn::Error::FsNoSuchRevision, /10/)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should be able to retrieve a property" do
|
69
|
+
write('/a', 'contents', true)
|
70
|
+
@repo.prop_get('/a', 'svn:mime-type', 1).should eql('application/octet-stream')
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should be able to list child directories" do
|
74
|
+
write('/a', 'contents')
|
75
|
+
write('/b', 'contents')
|
76
|
+
@repo.children('/').should eql(['a', 'b'])
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should not retrieve properties on non-existent paths" do
|
80
|
+
write('/a', 'contents')
|
81
|
+
attempting {
|
82
|
+
@repo.prop_get('/b', Svn::Core::PROP_REVISION_LOG)
|
83
|
+
}.should raise_error(Svn::Error::FsNotFound, /\/b/)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should fail to retrieve properties on a bad revision" do
|
87
|
+
write('/a', 'contents')
|
88
|
+
attempting {
|
89
|
+
@repo.prop_get('/a', Svn::Core::PROP_REVISION_AUTHOR, 5)
|
90
|
+
}.should raise_error(Svn::Error::FsNoSuchRevision, /5/)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'perforce2svn/subversion/svn_repo'
|
2
|
+
require 'spec_helpers'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module Perforce2Svn::Subversion
|
6
|
+
describe SvnTransaction do
|
7
|
+
include CommitHelper
|
8
|
+
|
9
|
+
before :each do
|
10
|
+
@repo = SvnRepo.new('REPO')
|
11
|
+
end
|
12
|
+
|
13
|
+
after :each do
|
14
|
+
@repo.delete!
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should be able to commit a single change" do
|
18
|
+
write('/a.txt', "this is some text\nthat\goes here")
|
19
|
+
@repo.pull_contents('/a.txt').should eql("this is some text\nthat\goes here")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be able to retrieve the updated file contents" do
|
23
|
+
write("/a.txt", "first commit")
|
24
|
+
write("/a.txt", 'second commit')
|
25
|
+
@repo.pull_contents('/a.txt').should eql('second commit')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be able to delete a file" do
|
29
|
+
write('/a', 'conent')
|
30
|
+
delete('/a')
|
31
|
+
attempting {
|
32
|
+
@repo.pull_contents('/a')
|
33
|
+
}.should raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can create multiple directories" do
|
37
|
+
@repo.exists?('/a/b/c').should be(false)
|
38
|
+
|
39
|
+
@repo.transaction('g', Time.new, 'l') do |txn|
|
40
|
+
txn.exists?('/a/b/c').should be(false)
|
41
|
+
txn.mkdir('/a/b/c')
|
42
|
+
end
|
43
|
+
|
44
|
+
@repo.exists?('/a/b/c').should be(true)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can delete all parent directories" do
|
48
|
+
write('/a/b/c/d.txt', 'some text')
|
49
|
+
write('/a/b.txt', 'other text')
|
50
|
+
delete('/a/b/c/d.txt')
|
51
|
+
|
52
|
+
@repo.exists?('/a/b/c').should be(false)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "will write binary mime types correctly" do
|
56
|
+
jpg = read_in('spec/integration/madmen_icon_bigger.jpg', 'rb')
|
57
|
+
write('/a.jpg', jpg, true)
|
58
|
+
|
59
|
+
@repo.pull_contents('/a.jpg').should eql(jpg)
|
60
|
+
@repo.prop_get('/a.jpg', 'svn:mime-type').should eql('application/octet-stream')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "will make sure that big files are retained correctly" do
|
64
|
+
hamlet = read_in('spec/integration/hamlet.txt')
|
65
|
+
write('/hamlet.txt', hamlet)
|
66
|
+
|
67
|
+
@repo.pull_contents('/hamlet.txt').should eql(hamlet)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "will handle symlinks correctly" do
|
71
|
+
write("/src.txt", "some content")
|
72
|
+
symlink('./src.txt', '/b.txt')
|
73
|
+
|
74
|
+
@repo.pull_contents('/b.txt').should eql('link ./src.txt')
|
75
|
+
@repo.prop_get('/b.txt', 'svn:special').should eql('*')
|
76
|
+
end
|
77
|
+
|
78
|
+
it "will return the most recent revision number on commit" do
|
79
|
+
write('/a.txt', 'content').should eql(1)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "will be able to find if a directory has children" do
|
83
|
+
write('/a/b.txt', 'content')
|
84
|
+
write('/a/c.txt', 'content')
|
85
|
+
@repo.transaction('gabe', Time.now, 'r') do |txn|
|
86
|
+
txn.has_children?('/a').should be(true)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it "will be able to copy paths" do
|
91
|
+
write('/a.txt', 'content')
|
92
|
+
@repo.transaction('gabe', Time.now, 'r') do |txn|
|
93
|
+
txn.copy('/a.txt', '/b.txt')
|
94
|
+
end
|
95
|
+
|
96
|
+
@repo.exists?('/a.txt').should be_true
|
97
|
+
@repo.exists?('/b.txt').should be_true
|
98
|
+
@repo.pull_contents('/b.txt').should eql('content')
|
99
|
+
end
|
100
|
+
|
101
|
+
it "will be able to move paths" do
|
102
|
+
write('/a.txt', 'content')
|
103
|
+
@repo.transaction('gabe', Time.now, 'r') do |txn|
|
104
|
+
txn.move('/a.txt', '/b.txt')
|
105
|
+
end
|
106
|
+
|
107
|
+
@repo.exists?('/a.txt').should be_false
|
108
|
+
@repo.exists?('/b.txt').should be_true
|
109
|
+
@repo.pull_contents('/b.txt').should eql('content')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'perforce2svn/cli'
|
2
|
+
require 'perforce2svn/errors'
|
3
|
+
require 'spec_helpers'
|
4
|
+
|
5
|
+
module Perforce2Svn
|
6
|
+
module CLIHelper
|
7
|
+
def parse(*args)
|
8
|
+
cli = CLI.new
|
9
|
+
args << '--repository'
|
10
|
+
args << 'here'
|
11
|
+
args << __FILE__
|
12
|
+
cli.parse!(args, true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe CLI do
|
17
|
+
include CLIHelper
|
18
|
+
|
19
|
+
it "should be able to parse the debug flag correctly" do
|
20
|
+
parse("--debug")[:debug].should be(true)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be able to retrieve the repository path" do
|
24
|
+
parse('-r', 'some/path')[:repository].should eql('here')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to parse the live path" do
|
28
|
+
parse('-l', '/')[:live_path].should eql('/')
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should be able to skip updates" do
|
32
|
+
parse('--skip-commands')[:skip_commands].should be(true)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be able to skip perforce" do
|
36
|
+
parse('--skip-perforce')[:skip_perforce].should be(true)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be able to run the analysis only" do
|
40
|
+
parse('-a')[:analyze_only].should be(true)
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "when validating the count format" do
|
44
|
+
it "should fail when the start revision is less than 1" do
|
45
|
+
attempting_to {
|
46
|
+
parse('-c', '0:4')
|
47
|
+
}.should raise_error(Choosy::ValidationError, /Minimum/)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should set -1 when given HEAD" do
|
51
|
+
parse('-c', '1:HEAD')[:changes].max.should eql(-1)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should fail when the end revision < 1" do
|
55
|
+
attempting_to {
|
56
|
+
parse('-c', '1:0')
|
57
|
+
}.should raise_error(Choosy::ValidationError, /Maximum/)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'perforce2svn/logging'
|
2
|
+
require 'perforce2svn/mapping/analyzer'
|
3
|
+
require 'perforce2svn/mapping/commands'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
module Perforce2Svn::Mapping
|
7
|
+
|
8
|
+
module AnalyzerHelper
|
9
|
+
def analyzing(*commands)
|
10
|
+
a = Analyzer.new(File.dirname(__FILE__))
|
11
|
+
a.check(commands)
|
12
|
+
end
|
13
|
+
|
14
|
+
def updater(file = nil)
|
15
|
+
file ||= __FILE__
|
16
|
+
tok = OpenStruct.new
|
17
|
+
tok.line_number = 1
|
18
|
+
Update.new(tok, nil, file)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "Mapping analyzer" do
|
23
|
+
include AnalyzerHelper
|
24
|
+
|
25
|
+
it "should be able to test whether updated files exist" do
|
26
|
+
analyzing(updater).should be(true)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should fail when updated files don't exist" do
|
30
|
+
analyzing(updater("nowhere")).should be(false)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be able to check multiple files" do
|
34
|
+
analyzing(updater("nowhere")).should be(false)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should be able to check when a file has a relative path" do
|
38
|
+
analyzing(updater(File.basename(__FILE__))).should be(true)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helpers'
|
2
|
+
require 'perforce2svn/mapping/branch_mapping'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Perforce2Svn::Mapping
|
6
|
+
module BranchMappingHelper
|
7
|
+
def map(p4, svn)
|
8
|
+
tok = OpenStruct.new
|
9
|
+
tok.line_number = 1
|
10
|
+
BranchMapping.new(tok, p4, svn)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Branch Mappings" do
|
15
|
+
include BranchMappingHelper
|
16
|
+
|
17
|
+
it "should be able to determine when a path doesn't match" do
|
18
|
+
bm = map('//depot/path/', '/svn/path/here')
|
19
|
+
bm.matches_perforce_path?('//depot/not/here').should be(false)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should be able to determine when a path doesn't match" do
|
23
|
+
bm = map('//depot/path/', '/svn/path/here')
|
24
|
+
bm.matches_perforce_path?('//depot/path/goes/here').should be(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to format the dotted P4 path" do
|
28
|
+
bm = map('//depot/path/', '/svn/path/here')
|
29
|
+
bm.p4_dotted.should eql('//depot/path/...')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be able to translate funky path characters correctly for subversion" do
|
33
|
+
bf = map("//p/", "/o/")
|
34
|
+
bf.to_svn_path("//p/%40/a").should eql("/o/@/a")
|
35
|
+
bf.to_svn_path("//p/%23/a").should eql("/o/#/a")
|
36
|
+
bf.to_svn_path("//p/%2a/a").should eql("/o/*/a")
|
37
|
+
bf.to_svn_path("//p/%25/a").should eql("/o/%/a")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'perforce2svn/mapping/lexer'
|
2
|
+
|
3
|
+
module Perforce2Svn
|
4
|
+
module Mapping
|
5
|
+
|
6
|
+
describe "Mapping lexer" do
|
7
|
+
it "should be able to parse a set of simple tokens in a line" do
|
8
|
+
lexer = Lexer.new(nil)
|
9
|
+
tok = lexer.tokenize('migrate this/that other/file')
|
10
|
+
tok.length.should eql(3)
|
11
|
+
tok[0].should eql('migrate')
|
12
|
+
tok[1].should eql('this/that')
|
13
|
+
tok[2].should eql('other/file')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should handle spaces in the path names" do
|
17
|
+
lexer = Lexer.new(nil)
|
18
|
+
tok = lexer.tokenize("migrate this/that\\ other/path will\\ be/something")
|
19
|
+
tok.length.should eql(3)
|
20
|
+
tok[0].should eql('migrate')
|
21
|
+
tok[1].should eql("this/that other/path")
|
22
|
+
tok[2].should eql("will be/something")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "will delete multiple spaces" do
|
26
|
+
lexer = Lexer.new(nil)
|
27
|
+
tok = lexer.tokenize(" migrate this/that and/a\\ nother ");
|
28
|
+
tok.length.should eql(3)
|
29
|
+
tok[0].should eql('migrate')
|
30
|
+
tok[1].should eql('this/that')
|
31
|
+
tok[2].should eql('and/a nother')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should leave off the comments at the end of lines" do
|
35
|
+
lexer = Lexer.new(nil)
|
36
|
+
tok = lexer.tokenize("this is a # comment string")
|
37
|
+
tok.length.should eql(3)
|
38
|
+
tok[0].should eql('this')
|
39
|
+
tok[2].should eql('a')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'perforce2svn/mapping/parser'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Perforce2Svn::Mapping
|
5
|
+
module ParserHelper
|
6
|
+
def parse(txt)
|
7
|
+
p = Parser.new
|
8
|
+
p.parse!(StringIO.new(txt), 'live')
|
9
|
+
end
|
10
|
+
|
11
|
+
def mappings(txt)
|
12
|
+
parse(txt)[:mappings]
|
13
|
+
end
|
14
|
+
|
15
|
+
def commands(txt)
|
16
|
+
parse(txt)[:commands]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Parser do
|
21
|
+
include ParserHelper
|
22
|
+
|
23
|
+
it "should fail when an unknown directive is found" do
|
24
|
+
parse(<<EOF
|
25
|
+
# A comment
|
26
|
+
not-directive arg
|
27
|
+
EOF
|
28
|
+
)[:failed].should be(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should be able to parse 'update's" do
|
32
|
+
parse("update /some/path")[:failed].should be(false)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should be able to parse 'migrate'" do
|
36
|
+
c = mappings("migrate //depot/path /svn/path")
|
37
|
+
c[0].class.should eql(BranchMapping)
|
38
|
+
c[0].line_number.should eql(1)
|
39
|
+
c[0].svn_path.should eql('/svn/path/')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should fail to parse the 'update' command without a svn prefix" do
|
43
|
+
parse("update src/main/pom.xml")[:failed].should be(true)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should parse the 'update' command when an svn prefix is available" do
|
47
|
+
parse(<<EOF
|
48
|
+
svn-prefix /some/path
|
49
|
+
update src/main/pom.xml
|
50
|
+
EOF
|
51
|
+
)[:failed].should be(false)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should parse the mapping file and return a list of migrations" do
|
55
|
+
m = mappings(<<EOF
|
56
|
+
migrate //depot/path /trunk/project
|
57
|
+
svn-prefix /trunk
|
58
|
+
migrate //depot/partition another-project
|
59
|
+
EOF
|
60
|
+
)
|
61
|
+
|
62
|
+
first = m[0]
|
63
|
+
first.line_number.should eql(1)
|
64
|
+
first.p4_path.should eql('//depot/path/')
|
65
|
+
first.svn_path.should eql('/trunk/project/')
|
66
|
+
|
67
|
+
second = m[1]
|
68
|
+
second.line_number.should eql(3)
|
69
|
+
second.p4_path.should eql('//depot/partition/')
|
70
|
+
second.svn_path.should eql('/trunk/another-project/')
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should be able to correctly parse updates" do
|
74
|
+
update = commands("update /src/dest.xml")[0]
|
75
|
+
update.class.should eql(Update)
|
76
|
+
update.line_number.should eql(1)
|
77
|
+
update.live_path.should eql('live/src/dest.xml')
|
78
|
+
update.svn_path.should eql('/src/dest.xml')
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should be able to correctly parse delete" do
|
82
|
+
delete = commands("delete /src/another.java")[0]
|
83
|
+
delete.class.should eql(Delete)
|
84
|
+
delete.line_number.should eql(1)
|
85
|
+
delete.svn_path.should eql('/src/another.java')
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should be able to correctly parse moves" do
|
89
|
+
move = commands("move /this/location.txt /to/here/location.txt")[0]
|
90
|
+
move.class.should eql(Move)
|
91
|
+
move.line_number.should eql(1)
|
92
|
+
move.svn_from.should eql('/this/location.txt')
|
93
|
+
move.svn_to.should eql('/to/here/location.txt')
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should be able to correctly parse copies" do
|
97
|
+
copy = commands("copy /src.txt /dest.txt")[0]
|
98
|
+
copy.class.should eql(Copy)
|
99
|
+
copy.line_number.should eql(1)
|
100
|
+
copy.svn_from.should eql('/src.txt')
|
101
|
+
copy.svn_to.should eql('/dest.txt')
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should be able to insert the svn prefix when a live path is calculated" do
|
105
|
+
update = commands("svn-prefix /trunk/project\nupdate src/dest.xml")[0]
|
106
|
+
update.live_path.should eql('live/trunk/project/src/dest.xml')
|
107
|
+
update.svn_path.should eql('/trunk/project/src/dest.xml')
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should fail when too many arguments are given to a command" do
|
111
|
+
parse('update /this/path /should/not/be')[:failed].should be(true)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should add the author to the context" do
|
115
|
+
parse('author An author')[:author].should eql('An author')
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should add the message to the context" do
|
119
|
+
parse(<<EOF
|
120
|
+
message this is a message that \
|
121
|
+
should span multiple lines \
|
122
|
+
and continue
|
123
|
+
EOF
|
124
|
+
)[:message].should eql('this is a message that should span multiple lines and continue')
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should be able to order the commands" do
|
128
|
+
cmds = commands(<<EOF
|
129
|
+
update /src/dest.xml
|
130
|
+
delete /src/another.java
|
131
|
+
EOF
|
132
|
+
)
|
133
|
+
|
134
|
+
cmds[0].class.should eql(Update)
|
135
|
+
cmds[0].line_number.should eql(1)
|
136
|
+
cmds[1].class.should eql(Delete)
|
137
|
+
cmds[1].line_number.should eql(2)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|