webmat-git_remote_branch 0.2.4 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
data/lib/version.rb ADDED
@@ -0,0 +1,14 @@
1
+ module GitRemoteBranch
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 2
5
+ TINY = 6
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.').freeze
8
+ end
9
+
10
+ NAME = 'git_remote_branch'.freeze
11
+ COMPLETE_NAME = "#{NAME} #{VERSION::STRING}".freeze
12
+ COMMAND_NAME = 'grb'.freeze
13
+ SHORT_NAME = COMMAND_NAME
14
+ end
data/tasks/gem.rake ADDED
@@ -0,0 +1,73 @@
1
+ require 'yaml'
2
+
3
+ require 'rake/gempackagetask'
4
+
5
+ task :clean => :clobber_package
6
+
7
+ spec = Gem::Specification.new do |s|
8
+ s.name = GitRemoteBranch::NAME
9
+ s.version = GitRemoteBranch::VERSION::STRING
10
+ s.summary = "git_remote_branch eases the interaction with remote branches"
11
+ s.description = "git_remote_branch is a learning tool to ease the interaction with " +
12
+ "remote branches in simple situations."
13
+
14
+ s.authors = ['Mathieu Martin', 'Carl Mercier']
15
+ s.email = "webmat@gmail.com"
16
+ s.homepage = "http://github.com/webmat/git_remote_branch"
17
+ s.rubyforge_project = 'grb'
18
+
19
+ s.has_rdoc = false
20
+
21
+ s.test_files = Dir['test/**/*']
22
+ s.files = Dir['**/*'].reject{|f| f =~ /\Apkg|\Acoverage|\.gemspec\Z/}
23
+
24
+ s.executable = 'grb'
25
+ s.bindir = "bin"
26
+ s.require_path = "lib"
27
+
28
+ s.add_dependency( 'colored', '>= 1.1' )
29
+ end
30
+
31
+ #Creates clobber_package, gem, package and repackage tasks
32
+ #Note on clobber_package: fortunately, this will clobber the CODE package
33
+ Rake::GemPackageTask.new(spec) do |p|
34
+ p.gem_spec = spec
35
+ end
36
+
37
+ TAG_COMMAND = "git tag -m 'Tagging version #{GitRemoteBranch::VERSION::STRING}' -a v#{GitRemoteBranch::VERSION::STRING}"
38
+ task :tag_warn do
39
+ puts "*" * 40,
40
+ "Don't forget to tag the release:",
41
+ '',
42
+ " " + TAG_COMMAND,
43
+ '',
44
+ "or run rake tag",
45
+ "*" * 40
46
+ end
47
+ task :tag do
48
+ sh TAG_COMMAND
49
+ end
50
+ task :gem => :tag_warn
51
+
52
+ namespace :gem do
53
+ desc "Update the gemspec for GitHub's gem server"
54
+ task :github do
55
+ File.open("#{GitRemoteBranch::NAME}.gemspec", 'w'){|f| f.puts YAML::dump(spec) }
56
+ puts "gemspec generated here: #{GitRemoteBranch::NAME}.gemspec"
57
+ end
58
+
59
+ desc 'Upload gem to rubyforge.org'
60
+ task :rubyforge => :gem do
61
+ sh 'rubyforge login'
62
+ sh "rubyforge add_release grb grb 'release #{GitRemoteBranch::VERSION::STRING}' pkg/#{spec.full_name}.gem"
63
+ sh "rubyforge add_file grb grb #{GitRemoteBranch::VERSION::STRING} pkg/#{spec.full_name}.gem"
64
+ end
65
+ end
66
+
67
+ task :install => [:clean, :gem] do
68
+ sh "#{SUDO} gem install pkg/#{spec.full_name}.gem"
69
+ end
70
+
71
+ task :uninstall do
72
+ sh "#{SUDO} gem uninstall -v #{GitRemoteBranch::VERSION::STRING} -x #{GitRemoteBranch::NAME}"
73
+ end
data/tasks/test.rake ADDED
@@ -0,0 +1,21 @@
1
+ require 'rake/testtask'
2
+
3
+ desc "Run all tests"
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.pattern = 'test/**/*_test.rb'
6
+ t.verbose = true
7
+ end
8
+
9
+ namespace :test do
10
+ desc "Run functional tests"
11
+ Rake::TestTask.new(:functional) do |t|
12
+ t.pattern = 'test/functional/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc "Run unit tests"
17
+ Rake::TestTask.new(:unit) do |t|
18
+ t.pattern = 'test/unit/**/*_test.rb'
19
+ t.verbose = true
20
+ end
21
+ end
@@ -0,0 +1,154 @@
1
+ require File.join( File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ class GRBTest < Test::Unit::TestCase
4
+ include ShouldaFunctionalHelpers
5
+
6
+ on_a_repository do
7
+ context "creating a branch in a local clone" do
8
+ setup do
9
+ in_directory_for :local1
10
+ run_grb_with 'create new_branch'
11
+ end
12
+
13
+ should_have_branch 'new_branch', :local, :remote
14
+
15
+ context "the remote repository" do
16
+ setup do
17
+ in_directory_for :remote
18
+ end
19
+
20
+ should_have_branch 'new_branch', :local
21
+ end
22
+
23
+ context "the other local clone, tracking the new branch" do
24
+ setup do
25
+ in_directory_for :local2
26
+ run_grb_with 'track new_branch'
27
+ end
28
+
29
+ should_have_branch 'new_branch', :local, :remote
30
+ end
31
+
32
+ context "then deleting the branch" do
33
+ setup do
34
+ run_grb_with 'delete new_branch'
35
+ end
36
+
37
+ should_not_have_branch 'new_branch', :local, :remote
38
+
39
+ context "the remote repository" do
40
+ setup do
41
+ in_directory_for :remote
42
+ end
43
+
44
+ should_not_have_branch 'new_branch', :local
45
+ end
46
+ end
47
+
48
+ context "renaming the branch" do
49
+ setup do
50
+ in_directory_for :local1
51
+ in_branch :new_branch
52
+ run_grb_with 'rename renamed_branch'
53
+ end
54
+
55
+ should_not_have_branch 'new_branch', :local, :remote
56
+ should_have_branch 'renamed_branch', :local, :remote
57
+
58
+ context "the remote repository" do
59
+ setup do
60
+ in_directory_for :remote
61
+ end
62
+
63
+ should_not_have_branch 'new_branch', :local
64
+ should_have_branch 'renamed_branch', :local
65
+ end
66
+ end
67
+ end
68
+
69
+ context "having a local only branch" do
70
+ setup do
71
+ in_directory_for :local1
72
+ execute "git branch my_branch"
73
+ end
74
+
75
+ should_have_branch 'my_branch', :local #Sanity check
76
+
77
+ context "remotizing the branch" do
78
+ setup do
79
+ run_grb_with 'publish my_branch'
80
+ end
81
+
82
+ should_have_branch 'my_branch', :remote
83
+
84
+ context "the remote repository" do
85
+ setup do
86
+ in_directory_for :remote
87
+ end
88
+
89
+ should_have_branch 'my_branch', :local
90
+ end
91
+ end
92
+ end
93
+
94
+ context "running grb with a detailed explain" do
95
+ setup do
96
+ in_directory_for :local1
97
+ @text = run_grb_with 'explain create teh_branch somewhere'
98
+ end
99
+
100
+ should "display the commands to run with the user-specified values, including current_branch" do
101
+ %w{master somewhere refs/heads/teh_branch}.each do |word|
102
+ assert_match(/#{word}/, @text)
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ in_a_non_git_directory do
109
+ context "displaying help" do
110
+ setup do
111
+ @text = run_grb_with 'help'
112
+ end
113
+
114
+ should "work" do
115
+ words_in_help = %w{create delete explain git_remote_branch}
116
+ words_in_help.each do |word|
117
+ assert_match(/#{word}/, @text)
118
+ end
119
+ end
120
+
121
+ should "not complain" do
122
+ assert_no_match(/not a git repository/i, @text)
123
+ end
124
+ end
125
+
126
+ context "running grb with a generic explain" do
127
+ setup do
128
+ @text = run_grb_with 'explain create'
129
+ end
130
+
131
+ should "display the commands to run with dummy values filled in" do
132
+ #Not sure if this will turn out to be too precise to my liking...
133
+ generic_words_in_explain_create = %w{
134
+ origin current_branch refs/heads/branch_to_create
135
+ git push fetch checkout}
136
+ generic_words_in_explain_create.each do |word|
137
+ assert_match(/#{word}/, @text)
138
+ end
139
+ end
140
+ end
141
+
142
+ context "running grb with a detailed explain" do
143
+ setup do
144
+ @text = run_grb_with 'explain create teh_branch somewhere'
145
+ end
146
+
147
+ should "display the commands to run with the user-specified values (except for current_branch)" do
148
+ %w{somewhere current_branch refs/heads/teh_branch}.each do |word|
149
+ assert_match(/#{word}/, @text)
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,14 @@
1
+ # Can be included in any class that responds to #each.
2
+ # Such as Array.
3
+ module CountDistinct
4
+ def count_all(purge_smaller_than=0)
5
+ h={}
6
+ self.each {|e|
7
+ h[e] ? h[e] += 1 : h[e] = 1
8
+ }
9
+ h.extract{|k,v| v >= purge_smaller_than}
10
+ end
11
+ end
12
+
13
+ Array.send :include, CountDistinct
14
+
@@ -0,0 +1,25 @@
1
+ class DirStack
2
+ attr_reader :dir_stack
3
+
4
+ def current_dir
5
+ dir_stack.size == 0 ? Dir.pwd : dir_stack.last
6
+ end
7
+
8
+ def pushd(dirname)
9
+ dir_stack.push(File.expand_path(dirname))
10
+ end
11
+
12
+ def popd
13
+ return [] if dir_stack.size==0
14
+ dir_stack.pop
15
+ dir_stack
16
+ end
17
+
18
+ def to_s
19
+ dir_stack.inspect
20
+ end
21
+
22
+ def initialize
23
+ @dir_stack = []
24
+ end
25
+ end
@@ -0,0 +1,63 @@
1
+ module Extractable
2
+ # Hash#extract(*keys) => Hash
3
+ # Hash#extract([keys]) => Hash
4
+ # Hash#extract{|k,v| predicate } => Hash
5
+ #
6
+ # Returns a new Hash that contains only the k,v pairs where the k was
7
+ # specified in the keys array.
8
+ # If any k in keys is not present in the original Hash, it's simply
9
+ # not the resulting Hash.
10
+ #
11
+ # This is very useful to check that a Hash contains at least some desired keys
12
+ # or to get a sanitized Hash out of the one we currently have.
13
+ #
14
+ # Examples:
15
+ # h = {:bob=>'Marley',:mom=>'Barley'}
16
+ # h.extract(:bob) #=> {:bob=>'Marley'}
17
+ # h.extract(:bob, :mom) #=> {:bob=>'Marley',:mom=>'Barley'}
18
+ # h.extract([:bob, :mom]) #=> {:bob=>'Marley',:mom=>'Barley'}
19
+ # h.extract(:sos) #=> {}
20
+
21
+ def extract(*args, &block)
22
+ if block_given?
23
+ extract_block(&block)
24
+ elsif args[0].is_a? Proc
25
+ extract_block(&args[0])
26
+ elsif args.size == 0
27
+ raise ArgumentError, "extract requires either an array of keys, a block or a proc"
28
+ else
29
+ extract_keys(args)
30
+ end
31
+ end
32
+
33
+ # Returns two hashes. The first contains all pairs for which the block evaluated to true,
34
+ # the second contains all the others.
35
+ def split(&block)
36
+ trues, falses = self.class.new, self.class.new
37
+ each_pair do |k,v|
38
+ if yield(k,v)
39
+ trues[k] = v
40
+ else
41
+ falses[k] = v
42
+ end
43
+ end
44
+ #each_pair{ |k,v| (yield(k,v) ? trues : falses)[k] = v }
45
+ return trues, falses
46
+ end
47
+
48
+ private
49
+ def extract_keys(*keys)
50
+ extracted = self.class.new #Can therefore be included in any hash-like container
51
+ keys.flatten.each { |k| extracted[k] = self[k] if self.include?(k) }
52
+ extracted
53
+ end
54
+
55
+ def extract_block(&block)
56
+ extracted = self.class.new
57
+ each_pair{ |k,v| extracted[k] = v if yield(k,v) }
58
+ extracted
59
+ end
60
+ end
61
+
62
+
63
+ Hash.send :include, Extractable
@@ -0,0 +1,33 @@
1
+ require 'fileutils'
2
+ require 'tmpdir'
3
+ require File.dirname(__FILE__) + '/temp_dir_helper'
4
+
5
+ # Instantiating a GitHelper object creates a temp directory containing 3 repos.
6
+ # 1 that's considered the remote repo and 2 peer local repos (local1 and local2).
7
+ # All 3 are synchronized with the same data (they contain a few dummy files).
8
+ # Once instantiated you can access the 3 full repo locations through attribute readers
9
+ # remote, local1 and local2.
10
+ class GitHelper < TempDirHelper
11
+
12
+ attr_reader :remote, :local1, :local2
13
+
14
+ def initialize
15
+ super('grb_test')
16
+
17
+ @remote = init_repo(directory, 'remote')
18
+ @local1 = clone_repo(@remote, directory, 'local1')
19
+ @local2 = clone_repo(@remote, directory, 'local2')
20
+ end
21
+
22
+ protected
23
+ def init_repo(path, name)
24
+ repo_dir = File.join(path, name)
25
+ `mkdir #{repo_dir}; cd $_; git init; touch file.txt; git add .; git commit -a -m "dummy file"`
26
+ repo_dir
27
+ end
28
+
29
+ def clone_repo(origin_path, clone_path, name)
30
+ `cd #{clone_path}; git clone #{File.join(origin_path, '.git')} #{name}`
31
+ return File.join(clone_path, name)
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ #require 'test/unit/assertionfailederror'
2
+ module MoreAssertions
3
+ include Test::Unit
4
+
5
+ def assert_false(condition, message = nil)
6
+ unless condition == false
7
+ raise AssertionFailedError, message || "assert_false failed"
8
+ end
9
+ end
10
+
11
+ def assert_array_content(expected_array, array, message = nil)
12
+ unless expected_array.count_all == array.count_all
13
+ raise AssertionFailedError, message || "arrays did not have the same content. Expected #{expected_array.inspect}, got #{array.inspect}"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,106 @@
1
+ module ShouldaFunctionalHelpers
2
+ include CaptureFu
3
+ GRB_COMMAND = File.expand_path(File.dirname(__FILE__) + '/../../bin/grb') unless defined?(GRB_COMMAND)
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ base.class_eval do
8
+ include ::ShouldaFunctionalHelpers::InstanceMethods
9
+ end
10
+ end
11
+
12
+ module InstanceMethods
13
+ def current_dir
14
+ @current_dir || raise("@current_dir is not set. Warning, Will Robinson!")
15
+ end
16
+
17
+ def current_dir=(value)
18
+ @current_dir = value
19
+ end
20
+
21
+ # Switches to one of the directories created by GitHelper:
22
+ # :local1, :local2, :non_git or :remote
23
+ # This affects commands run with ``, system and so on.
24
+ def in_directory_for(dir)
25
+ # Just a reminder for my dumb head
26
+ raise "'in_directory_for' depends on @gh being set" unless @gh
27
+
28
+ @current_dir = eval("@gh.#{dir}")
29
+ end
30
+
31
+ def in_branch(branch)
32
+ execute "git checkout #{branch}"
33
+ end
34
+
35
+
36
+ def run_grb_with(params='')
37
+ execute "#{GRB_COMMAND} #{params}"
38
+ end
39
+
40
+ def execute(command)
41
+ errno, returned_string = capture_process_output("cd #{current_dir} ; #{command}")
42
+ returned_string
43
+ end
44
+
45
+ private
46
+ def get_branch_location(location)
47
+ case location.to_sym
48
+ when :local
49
+ args = '-l'
50
+ when :remote
51
+ args = '-r'
52
+ else
53
+ raise ArgumentError, "Unknown branch location: #{location.inspect}"
54
+ end
55
+ end
56
+ end
57
+
58
+ module ClassMethods
59
+ def should_have_branch(what_branch, *wheres)
60
+ wheres.flatten.each do |where|
61
+ should "have the branch '#{what_branch}' #{where == :local ? 'locally' : 'remotely'}" do
62
+ args = get_branch_location(where)
63
+ assert_match(/#{what_branch}/, execute("git branch #{args}"))
64
+ end
65
+ end
66
+ end
67
+
68
+ def should_not_have_branch(what_branch, *wheres)
69
+ wheres.flatten.each do |where|
70
+ should "not have the branch '#{what_branch}' #{where == :local ? 'locally' : 'remotely'}" do
71
+ args = get_branch_location(where)
72
+ assert_no_match(/#{what_branch}/, execute("git branch #{args}"))
73
+ end
74
+ end
75
+ end
76
+
77
+ def on_a_repository
78
+ context "on a new repository" do
79
+ setup do
80
+ @gh = GitHelper.new
81
+ end
82
+
83
+ teardown do
84
+ @gh.cleanup
85
+ end
86
+
87
+ yield
88
+ end
89
+ end
90
+
91
+ def in_a_non_git_directory
92
+ context "on a non-git related directory" do
93
+ setup do
94
+ @temp_dir = TempDirHelper.new
95
+ @current_dir = @temp_dir.directory
96
+ end
97
+
98
+ teardown do
99
+ @temp_dir.cleanup
100
+ end
101
+
102
+ yield
103
+ end
104
+ end
105
+ end
106
+ end