francois-piston 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/History.txt +19 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +109 -0
  4. data/README.txt +136 -0
  5. data/VERSION.yml +4 -0
  6. data/bin/piston +5 -0
  7. data/lib/piston.rb +18 -0
  8. data/lib/piston/cli.rb +391 -0
  9. data/lib/piston/commands.rb +4 -0
  10. data/lib/piston/commands/base.rb +44 -0
  11. data/lib/piston/commands/convert.rb +26 -0
  12. data/lib/piston/commands/diff.rb +12 -0
  13. data/lib/piston/commands/import.rb +43 -0
  14. data/lib/piston/commands/info.rb +14 -0
  15. data/lib/piston/commands/lock_unlock.rb +21 -0
  16. data/lib/piston/commands/status.rb +40 -0
  17. data/lib/piston/commands/update.rb +34 -0
  18. data/lib/piston/commands/upgrade.rb +20 -0
  19. data/lib/piston/git.rb +13 -0
  20. data/lib/piston/git/client.rb +76 -0
  21. data/lib/piston/git/commit.rb +114 -0
  22. data/lib/piston/git/repository.rb +63 -0
  23. data/lib/piston/git/working_copy.rb +142 -0
  24. data/lib/piston/repository.rb +61 -0
  25. data/lib/piston/revision.rb +83 -0
  26. data/lib/piston/svn.rb +15 -0
  27. data/lib/piston/svn/client.rb +88 -0
  28. data/lib/piston/svn/repository.rb +67 -0
  29. data/lib/piston/svn/revision.rb +112 -0
  30. data/lib/piston/svn/working_copy.rb +182 -0
  31. data/lib/piston/version.rb +9 -0
  32. data/lib/piston/working_copy.rb +334 -0
  33. data/lib/subclass_responsibility_error.rb +2 -0
  34. data/test/integration_helpers.rb +35 -0
  35. data/test/spec_suite.rb +4 -0
  36. data/test/test_helper.rb +83 -0
  37. data/test/unit/git/commit/test_checkout.rb +31 -0
  38. data/test/unit/git/commit/test_each.rb +30 -0
  39. data/test/unit/git/commit/test_rememberance.rb +22 -0
  40. data/test/unit/git/commit/test_validation.rb +34 -0
  41. data/test/unit/git/repository/test_at.rb +23 -0
  42. data/test/unit/git/repository/test_basename.rb +12 -0
  43. data/test/unit/git/repository/test_branchanme.rb +15 -0
  44. data/test/unit/git/repository/test_guessing.rb +32 -0
  45. data/test/unit/git/working_copy/test_copying.rb +25 -0
  46. data/test/unit/git/working_copy/test_creation.rb +22 -0
  47. data/test/unit/git/working_copy/test_existence.rb +18 -0
  48. data/test/unit/git/working_copy/test_finalization.rb +15 -0
  49. data/test/unit/git/working_copy/test_guessing.rb +35 -0
  50. data/test/unit/git/working_copy/test_rememberance.rb +22 -0
  51. data/test/unit/svn/repository/test_at.rb +19 -0
  52. data/test/unit/svn/repository/test_basename.rb +24 -0
  53. data/test/unit/svn/repository/test_guessing.rb +45 -0
  54. data/test/unit/svn/revision/test_checkout.rb +28 -0
  55. data/test/unit/svn/revision/test_each.rb +22 -0
  56. data/test/unit/svn/revision/test_rememberance.rb +38 -0
  57. data/test/unit/svn/revision/test_validation.rb +50 -0
  58. data/test/unit/svn/working_copy/test_copying.rb +26 -0
  59. data/test/unit/svn/working_copy/test_creation.rb +16 -0
  60. data/test/unit/svn/working_copy/test_existence.rb +23 -0
  61. data/test/unit/svn/working_copy/test_externals.rb +56 -0
  62. data/test/unit/svn/working_copy/test_finalization.rb +17 -0
  63. data/test/unit/svn/working_copy/test_guessing.rb +18 -0
  64. data/test/unit/svn/working_copy/test_rememberance.rb +26 -0
  65. data/test/unit/test_info.rb +37 -0
  66. data/test/unit/test_lock_unlock.rb +47 -0
  67. data/test/unit/test_repository.rb +51 -0
  68. data/test/unit/test_revision.rb +31 -0
  69. data/test/unit/working_copy/test_guessing.rb +35 -0
  70. data/test/unit/working_copy/test_info.rb +14 -0
  71. data/test/unit/working_copy/test_rememberance.rb +42 -0
  72. data/test/unit/working_copy/test_validate.rb +63 -0
  73. metadata +178 -0
@@ -0,0 +1,2 @@
1
+ class SubclassResponsibilityError < RuntimeError
2
+ end
@@ -0,0 +1,35 @@
1
+ PISTON_ROOT = Pathname.new(File.dirname(__FILE__)).parent.realpath
2
+
3
+ def logger
4
+ @logger ||= Log4r::Logger["test"]
5
+ end
6
+
7
+ def runcmd(cmd, *args)
8
+ cmdline = [cmd]
9
+ cmdline += args
10
+ cmdline = cmdline.flatten.map {|s| s.to_s}.join(" ")
11
+ logger.debug "> #{cmdline}"
12
+
13
+ output = `#{cmdline}`
14
+ logger.debug "< #{output}"
15
+ return output if $?.success?
16
+ raise CommandFailed, "Could not run %s, exit status: <%d>\n===\n%s\n===" % [cmdline.inspect, $?.exitstatus, output]
17
+ end
18
+
19
+ def svn(*args)
20
+ runcmd(:svn, *args)
21
+ end
22
+
23
+ def svnadmin(*args)
24
+ runcmd(:svnadmin, *args)
25
+ end
26
+
27
+ def git(*args)
28
+ runcmd(:git, *args)
29
+ end
30
+
31
+ def piston(*args)
32
+ runcmd(:ruby, "-I", PISTON_ROOT + "lib", PISTON_ROOT + "bin/piston", *args)
33
+ end
34
+
35
+ class CommandFailed < RuntimeError; end
@@ -0,0 +1,4 @@
1
+ dir = File.dirname(__FILE__)
2
+ Dir["#{dir}/**/test_*.rb"].each do |file|
3
+ require file
4
+ end
@@ -0,0 +1,83 @@
1
+ require "test/unit"
2
+ require "rubygems"
3
+ require "mocha"
4
+ require "log4r"
5
+ require "fileutils"
6
+
7
+ begin
8
+ require "turn"
9
+ rescue LoadError
10
+ # NOP: ignore, this is not a real dependency
11
+ end
12
+
13
+ require File.expand_path("#{File.dirname(__FILE__)}/../config/requirements")
14
+ require File.expand_path("#{File.dirname(__FILE__)}/integration_helpers")
15
+ require "find"
16
+
17
+ module Test
18
+ module Unit
19
+ module Assertions
20
+ def deny(boolean, message = nil)
21
+ message = build_message message, '<?> is not false or nil.', boolean
22
+ assert_block message do
23
+ not boolean
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ class Piston::TestCase < Test::Unit::TestCase
31
+ class << self
32
+ def logger
33
+ @@logger ||= Log4r::Logger["test"]
34
+ end
35
+ end
36
+
37
+ attr_reader :pathnames
38
+ def setup
39
+ super
40
+ @pathnames = []
41
+ end
42
+
43
+ def teardown
44
+ pathnames.each do |pathname|
45
+ pathname.rmtree if File.exists?(pathname)
46
+ end
47
+ super
48
+ end
49
+
50
+ def run(*args)
51
+ return if method_name.to_sym == :default_test && self.class == Piston::TestCase
52
+ super
53
+ end
54
+
55
+ def mkpath(path_or_pathname)
56
+ returning(path_or_pathname.is_a?(Pathname) ? path_or_pathname : Pathname.new(File.expand_path(path_or_pathname))) do |path|
57
+ path.mkpath
58
+ pathnames.push(path)
59
+ end
60
+ end
61
+
62
+ def logger
63
+ self.class.logger
64
+ end
65
+ end
66
+
67
+ LOG_DIR = Pathname.new(File.expand_path("#{File.dirname(__FILE__)}/../log")) unless Object::const_defined?(:LOG_DIR)
68
+ LOG_DIR.mkdir rescue nil
69
+
70
+ Log4r::Logger.root.level = Log4r::DEBUG
71
+
72
+ Log4r::Logger.new("main")
73
+ Log4r::Logger.new("handler")
74
+ Log4r::Logger.new("handler::client")
75
+ Log4r::Logger.new("handler::client::out")
76
+ Log4r::Logger.new("test")
77
+
78
+ FileUtils.touch("#{LOG_DIR}/test.log")
79
+ Log4r::FileOutputter.new("log", :trunc => true, :filename => (LOG_DIR + "test.log").realpath.to_s)
80
+
81
+ Log4r::Logger["main"].add "log"
82
+ Log4r::Logger["handler"].add "log"
83
+ Log4r::Logger["test"].add "log"
@@ -0,0 +1,31 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitCommitCheckout < Piston::TestCase
4
+ def setup
5
+ super
6
+ @repos = mock("repos")
7
+ @repos.stubs(:url).returns("git://a.repos.com/project.git")
8
+ @reposdir = Pathname.new("tmp/.repos.tmp.git")
9
+ end
10
+
11
+ def test_clones_repository_at_indicated_path
12
+ @sha1 = "a9302"
13
+ @commit = Piston::Git::Commit.new(@repos, @sha1)
14
+ @commit.expects(:git).with(:clone, @repos.url, @reposdir)
15
+ @commit.expects(:git).with(:checkout, "-b", "my-#{@sha1}", @sha1)
16
+ @commit.expects(:git).with(:log, "-n", "1").returns("commit 922b12a6bcbb6f6a2cec60bcf5de17118086080a\nAuthor: Fran\303\247ois Beausoleil <francois@teksol.info>\nDate: Fri Mar 14 13:28:41 2008 -0400\n\n Changed how dependencies are found and managed, by using config/requirements.rb everywhere.\n \n Updated test/test_helper.rb where appropriate.\n")
17
+ Dir.expects(:chdir).with(@reposdir).yields
18
+ @commit.checkout_to(@reposdir)
19
+ end
20
+
21
+ def test_cloning_head_finds_head_commit
22
+ @sha1 = "master"
23
+ @commit = Piston::Git::Commit.new(@repos, @sha1)
24
+ @commit.expects(:git).with(:clone, @repos.url, @reposdir)
25
+ @commit.expects(:git).with(:checkout, "-b", "my-#{@sha1}", @sha1)
26
+ @commit.expects(:git).with(:log, "-n", "1").returns("commit 922b12a6bcbb6f6a2cec60bcf5de17118086080a\nAuthor: Fran\303\247ois Beausoleil <francois@teksol.info>\nDate: Fri Mar 14 13:28:41 2008 -0400\n\n Changed how dependencies are found and managed, by using config/requirements.rb everywhere.\n \n Updated test/test_helper.rb where appropriate.\n")
27
+ Dir.expects(:chdir).with(@reposdir).yields
28
+ @commit.checkout_to(@reposdir)
29
+ assert_equal "922b12a6bcbb6f6a2cec60bcf5de17118086080a", @commit.sha1
30
+ end
31
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitCommitEach < Piston::TestCase
4
+ def setup
5
+ super
6
+ @repos = mock("repository")
7
+ @repos.stubs(:url).returns("git://github.com/francois/arepos.git")
8
+ @tmpdir = mkpath("tmp/.arepos.tmp.git")
9
+
10
+ @commit = Piston::Git::Commit.new(@repos, "ab"*20)
11
+ @commit.stubs(:git).returns("commit " + "ab" * 20)
12
+ @commit.checkout_to(@tmpdir)
13
+ end
14
+
15
+ def test_prunes_search_tree_on_dot_git_directory
16
+ @tmpdir.expects(:find).yields(@tmpdir + ".git")
17
+ assert_throws :prune do
18
+ @commit.each do |relpath|
19
+ # Can't assert anything
20
+ end
21
+ end
22
+ end
23
+
24
+ def test_yields_paths_relative_to_working_copy
25
+ @tmpdir.expects(:find).yields(@tmpdir + "a.rb")
26
+ @commit.each do |relpath|
27
+ assert_equal Pathname.new("a.rb"), relpath
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitCommitRememberance < Piston::TestCase
4
+ def setup
5
+ super
6
+ @repos = mock("repository")
7
+ @repos.stubs(:url).returns("git://github.com/francois/arepos.git")
8
+
9
+ @reposdir = Pathname.new("tmp/repos.git")
10
+ @commit = Piston::Git::Commit.new(@repos, "ab"*20)
11
+ @commit.stubs(:git).with("ls-remote", @repos.url, @commit.commit).returns("b"*40)
12
+ @values = @commit.remember_values
13
+ end
14
+
15
+ def test_remembers_original_commit_sha1
16
+ assert_equal @values[Piston::Git::COMMIT], @commit.sha1
17
+ end
18
+
19
+ def test_remembers_original_branch_name
20
+ assert_equal @values[Piston::Git::BRANCH], @commit.revision
21
+ end
22
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitCommitValidation < Piston::TestCase
4
+ def setup
5
+ super
6
+ @repository = mock("repository")
7
+ @repository.stubs(:url).returns("git://my-git-repos/my-project.git")
8
+ end
9
+
10
+ def test_is_invalid_if_cannot_ls_remote_repository
11
+ commit = new_commit("HEAD")
12
+ commit.expects(:git).with("ls-remote", @repository.url).raises(Piston::Git::Client::CommandError)
13
+ assert_raise Piston::Git::Commit::Gone do
14
+ commit.validate!
15
+ end
16
+ end
17
+
18
+ def test_is_valid_when_ls_remote_succeeds
19
+ commit = new_commit("HEAD")
20
+ commit.expects(:git).with("ls-remote", @repository.url).returns(INFO)
21
+ assert_nothing_raised do
22
+ commit.validate!
23
+ end
24
+ end
25
+
26
+ protected
27
+ def new_commit(commit, recalled_values={})
28
+ Piston::Git::Commit.new(@repository, commit, recalled_values)
29
+ end
30
+
31
+ INFO = <<EOF
32
+ a7c46c702243f145a4089b0cb33d189870f1ae53 HEAD
33
+ EOF
34
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitRepositoryAt < Piston::TestCase
4
+ def setup
5
+ super
6
+ @repos = Piston::Git::Repository.new("git://a.repos.com/project.git")
7
+ end
8
+
9
+ def test_returns_a_piston_git_commit
10
+ Piston::Git::Commit.expects(:new).with(@repos, "a93029").returns(commit = mock("commit"))
11
+ assert_equal commit, @repos.at("a93029")
12
+ end
13
+
14
+ def test_returns_a_piston_git_commit_at_head_when_appropriate
15
+ Piston::Git::Commit.expects(:new).with(@repos, "HEAD").returns(commit = mock("commit"))
16
+ assert_equal commit, @repos.at(:head)
17
+ end
18
+
19
+ def test_returns_a_git_commit_using_recalled_values
20
+ Piston::Git::Commit.expects(:new).with(@repos, "a"*40, Piston::Git::COMMIT => "a"*40).returns(commit = mock("commit"))
21
+ assert_equal commit, @repos.at(Piston::Git::COMMIT => "a"*40)
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitRepositoryBasename < Piston::TestCase
4
+ def test_basename_is_urls_last_component_minus_dot_git
5
+ assert_equal "piston", basename("git://github.com/francois/piston.git")
6
+ end
7
+
8
+ private
9
+ def basename(url)
10
+ Piston::Git::Repository.new(url).basename
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitRepositoryBranchname < Piston::TestCase
4
+ def test_branchname_is_nil_when_no_branch_in_url
5
+ assert_nil Piston::Git::Repository.new("git://github.com/francois/piston.git").branchname
6
+ end
7
+
8
+ def test_branchname_is_branch_when_branch_in_url
9
+ assert_equal "branch", Piston::Git::Repository.new("git://github.com/francois/piston.git?branch").branchname
10
+ end
11
+
12
+ def test_url_does_not_include_branchname
13
+ assert_equal "git://github.com/francois/piston.git", Piston::Git::Repository.new("git://github.com/francois/piston.git?branch").url
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitRepositoryGuessing < Piston::TestCase
4
+ def test_understands_git_protocol
5
+ assert Piston::Git::Repository.understands_url?("git://github.com/francois/piston.git")
6
+ end
7
+
8
+ def test_understands_git_ssh_protocol
9
+ Piston::Git::Repository.expects(:git).with("ls-remote", "--heads", "git@github.com:francois/piston.git").returns("ab"*20 + " refs/heads/master")
10
+ assert Piston::Git::Repository.understands_url?("git@github.com:francois/piston.git")
11
+ end
12
+
13
+ def test_understand_http_when_heads_returned
14
+ Piston::Git::Repository.expects(:git).with("ls-remote", "--heads", "http://github.com/francois/piston.git").returns("ab"*20 + " refs/heads/master")
15
+ assert Piston::Git::Repository.understands_url?("http://github.com/francois/piston.git")
16
+ end
17
+
18
+ def test_does_not_understand_http_when_no_heads
19
+ Piston::Git::Repository.expects(:git).with("ls-remote", "--heads", "http://github.com/francois/piston.git").returns("")
20
+ deny Piston::Git::Repository.understands_url?("http://github.com/francois/piston.git")
21
+ end
22
+
23
+ def test_asks_url_when_ssh_protocol
24
+ Piston::Git::Repository.expects(:git).with("ls-remote", "--heads", "ssh://francois@github.com/francois/piston.git").returns("ab"*20 + " refs/heads/master")
25
+ assert Piston::Git::Repository.understands_url?("ssh://francois@github.com/francois/piston.git")
26
+ end
27
+
28
+ def test_asks_base_url_when_named_branch_in_url
29
+ Piston::Git::Repository.expects(:git).with("ls-remote", "--heads", "ssh://francois@github.com/francois/piston.git").returns("ab"*20 + " refs/heads/master")
30
+ assert Piston::Git::Repository.understands_url?("ssh://francois@github.com/francois/piston.git?convert")
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitWorkingCopyCopying < Piston::TestCase
4
+ def setup
5
+ super
6
+ @wcdir = mkpath("tmp/wc")
7
+ @wc = Piston::Git::WorkingCopy.new(@wcdir)
8
+ @wc.stubs(:git)
9
+ end
10
+
11
+ def test_copies_file
12
+ files = ["file.rb"]
13
+ files.expects(:copy_to).with("file.rb", @wcdir + files.first)
14
+ @wc.copy_from(files)
15
+ end
16
+
17
+ def test_ensures_directories_are_created
18
+ files = ["file/a.rb"]
19
+ @wcdir.expects(:+).with(files.first).returns(target = mock("target"))
20
+ target.expects(:dirname).returns(target)
21
+ target.expects(:mkdir)
22
+ files.expects(:copy_to).with("file/a.rb", target)
23
+ @wc.copy_from(files)
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitWorkingCopyCreation < Piston::TestCase
4
+ def setup
5
+ super
6
+ @wcdir = mkpath("tmp/wc")
7
+ @wc = Piston::Git::WorkingCopy.new(@wcdir)
8
+ @wc.stubs(:git)
9
+ end
10
+
11
+ def test_create_does_a_simple_mkpath
12
+ @wcdir.expects(:mkpath)
13
+ @wc.create
14
+ end
15
+
16
+ def test_create_succeeds_even_if_mkpath_fails
17
+ @wcdir.expects(:mkpath).raises(Errno::EEXIST)
18
+ assert_nothing_raised do
19
+ @wc.create
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitWorkingCopyExistence < Piston::TestCase
4
+ def setup
5
+ super
6
+ @wc = Piston::Git::WorkingCopy.new("tmp/wc")
7
+ @wcdir = @wc.path
8
+ end
9
+
10
+ def test_exist_false_when_no_dir
11
+ deny @wc.exist?
12
+ end
13
+
14
+ def test_exist_true_when_dir_present
15
+ @wcdir.mkdir
16
+ assert @wc.exist?
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitWorkingCopyFinalization < Piston::TestCase
4
+ def setup
5
+ super
6
+ @wcdir = mkpath("tmp/wc")
7
+ @wc = Piston::Git::WorkingCopy.new(@wcdir)
8
+ end
9
+
10
+ def test_finalize_adds_path_to_git
11
+ Dir.expects(:chdir).with(@wcdir).yields
12
+ @wc.expects(:git).with(:add, ".")
13
+ @wc.finalize
14
+ end
15
+ end
@@ -0,0 +1,35 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../../../test_helper")
2
+
3
+ class Piston::Git::TestGitWorkingCopyGuessing < Piston::TestCase
4
+ def setup
5
+ super
6
+ @dir = mkpath("tmp/wc")
7
+ end
8
+
9
+ def test_does_git_status_on_directory
10
+ Dir.expects(:chdir).with(@dir).yields
11
+ Piston::Git::WorkingCopy.expects(:git).with(:status).returns("# On branch master
12
+ nothing to commit (working directory clean)
13
+ ")
14
+ assert Piston::Git::WorkingCopy.understands_dir?(@dir)
15
+ end
16
+
17
+ def test_does_git_status_on_parent_directories_recursively
18
+ @wc = @dir
19
+ @tmp = @wc.parent
20
+ @root = @tmp.parent
21
+
22
+ Dir.expects(:chdir).with(@dir).raises(Errno::ENOENT)
23
+ Dir.expects(:chdir).with(@tmp).raises(Errno::ENOENT)
24
+ Dir.expects(:chdir).with(@root).yields
25
+ Piston::Git::WorkingCopy.expects(:git).with(:status).returns("# On branch master
26
+ nothing to commit (working directory clean)
27
+ ")
28
+ assert Piston::Git::WorkingCopy.understands_dir?(@dir)
29
+ end
30
+
31
+ def test_denies_when_git_unavailable
32
+ Piston::Git::WorkingCopy.stubs(:git).raises(Piston::Git::Client::BadCommand)
33
+ deny Piston::Git::WorkingCopy.understands_dir?(@dir)
34
+ end
35
+ end