kch-git_remote_branch 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +32 -0
- data/LICENSE +18 -0
- data/README.rdoc +184 -0
- data/Rakefile +17 -0
- data/bin/grb +44 -0
- data/lib/constants.rb +5 -0
- data/lib/git_remote_branch.rb +164 -0
- data/lib/param_reader.rb +63 -0
- data/lib/state.rb +42 -0
- data/lib/version.rb +14 -0
- data/tasks/gem.rake +89 -0
- data/tasks/rdoc.rake +15 -0
- data/tasks/test.rake +18 -0
- data/test/functional/grb_test.rb +188 -0
- data/test/helpers/array_extensions.rb +14 -0
- data/test/helpers/constants.rb +15 -0
- data/test/helpers/extractable.rb +63 -0
- data/test/helpers/git_helper.rb +40 -0
- data/test/helpers/in_dir.rb +10 -0
- data/test/helpers/more_assertions.rb +16 -0
- data/test/helpers/shoulda_functional_helpers.rb +152 -0
- data/test/helpers/shoulda_unit_helpers.rb +88 -0
- data/test/helpers/temp_dir_helper.rb +38 -0
- data/test/test_helper.rb +36 -0
- data/test/unit/git_helper_test.rb +30 -0
- data/test/unit/git_remote_branch_test.rb +39 -0
- data/test/unit/param_reader_test.rb +215 -0
- data/test/unit/state_test.rb +56 -0
- data/vendor/capture_fu.rb +58 -0
- metadata +120 -0
data/lib/param_reader.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module GitRemoteBranch
|
2
|
+
|
3
|
+
private
|
4
|
+
HELP_PARAMS = {:action => :help}
|
5
|
+
|
6
|
+
public
|
7
|
+
def read_params(argv)
|
8
|
+
#TODO Some validation on the params
|
9
|
+
|
10
|
+
p={}
|
11
|
+
p[:silent] = silent!(argv)
|
12
|
+
p[:explain] = explain_mode!(argv)
|
13
|
+
|
14
|
+
p[:action] = get_action(argv[0]) or return HELP_PARAMS
|
15
|
+
|
16
|
+
return HELP_PARAMS if p[:action] == :help
|
17
|
+
|
18
|
+
p[:branch] = get_branch(argv[1])
|
19
|
+
p[:origin] = get_origin(argv[2])
|
20
|
+
|
21
|
+
# If in explain mode, the user doesn't have to specify a branch or be on in
|
22
|
+
# actual repo to get the explanation.
|
23
|
+
# Of course if he is, the explanation will be made better by using contextual info.
|
24
|
+
if p[:explain]
|
25
|
+
p[:branch] ||= "branch_to_#{p[:action]}"
|
26
|
+
p[:current_branch] = begin
|
27
|
+
get_current_branch
|
28
|
+
rescue NotOnGitRepositoryError, InvalidBranchError
|
29
|
+
'current_branch'
|
30
|
+
end
|
31
|
+
|
32
|
+
else
|
33
|
+
return HELP_PARAMS unless p[:branch]
|
34
|
+
p[:current_branch] = get_current_branch
|
35
|
+
end
|
36
|
+
return p
|
37
|
+
end
|
38
|
+
|
39
|
+
def explain_mode!(argv)
|
40
|
+
if argv[0].to_s.downcase == 'explain'
|
41
|
+
argv.shift
|
42
|
+
true
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def silent!(argv)
|
49
|
+
!!argv.delete('--silent')
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_action(action)
|
53
|
+
ALIAS_REVERSE_MAP[action.to_s.downcase]
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_branch(branch)
|
57
|
+
branch
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_origin(origin)
|
61
|
+
return origin || 'origin'
|
62
|
+
end
|
63
|
+
end
|
data/lib/state.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module GitRemoteBranch
|
2
|
+
include ::CaptureFu
|
3
|
+
|
4
|
+
public
|
5
|
+
def get_current_branch
|
6
|
+
local_branch_information[0]
|
7
|
+
end
|
8
|
+
|
9
|
+
def local_branches
|
10
|
+
local_branch_information[1]
|
11
|
+
end
|
12
|
+
|
13
|
+
def git_found?
|
14
|
+
ret, msg = capture_process_output "#{GIT} --version"
|
15
|
+
ret == 0
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
# Returns an array of 2 elements: [current_branch, [all local branches]]
|
20
|
+
def local_branch_information
|
21
|
+
#This is sensitive to checkouts of branches specified with wrong case
|
22
|
+
|
23
|
+
listing = capture_process_output("#{LOCAL_BRANCH_LISTING_COMMAND}")[1]
|
24
|
+
|
25
|
+
raise(NotOnGitRepositoryError, listing.chomp) if listing =~ /Not a git repository/i
|
26
|
+
if listing =~ /\(no branch\)/
|
27
|
+
raise InvalidBranchError, ["Couldn't identify the current local branch. The branch listing was:",
|
28
|
+
LOCAL_BRANCH_LISTING_COMMAND.red,
|
29
|
+
listing].join("\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
current_branch = nil
|
33
|
+
branches = listing.split("\n").map do |line|
|
34
|
+
current = line.include? '*'
|
35
|
+
clean_line = line.gsub('*','').strip
|
36
|
+
current_branch = clean_line if current
|
37
|
+
clean_line
|
38
|
+
end
|
39
|
+
|
40
|
+
return current_branch, branches
|
41
|
+
end
|
42
|
+
end
|
data/lib/version.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module GitRemoteBranch
|
2
|
+
module VERSION #:nodoc:
|
3
|
+
MAJOR = 0
|
4
|
+
MINOR = 3
|
5
|
+
TINY = 0
|
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,89 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = GitRemoteBranch::NAME
|
7
|
+
s.version = GitRemoteBranch::VERSION::STRING
|
8
|
+
s.summary = "git_remote_branch eases the interaction with remote branches"
|
9
|
+
s.description = "git_remote_branch is a learning tool to ease the interaction with " +
|
10
|
+
"remote branches in simple situations."
|
11
|
+
|
12
|
+
s.authors = ['Mathieu Martin', 'Carl Mercier']
|
13
|
+
s.email = "webmat@gmail.com"
|
14
|
+
s.homepage = "http://github.com/webmat/git_remote_branch"
|
15
|
+
s.rubyforge_project = 'grb'
|
16
|
+
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.extra_rdoc_files << 'README.rdoc'
|
19
|
+
s.rdoc_options << '--main' << 'README.rdoc' << '--exclude' << 'lib'
|
20
|
+
|
21
|
+
s.test_files = Dir['test/**/*'].reject{|f| f =~ /test_runs/}
|
22
|
+
s.files = Dir['**/*'].reject{|f| f =~ /\Apkg|\Acoverage|\Ardoc|test_runs|\.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
|
+
puts "Upload tags to repo with 'git push --tags'"
|
50
|
+
end
|
51
|
+
task :gem => :tag_warn
|
52
|
+
|
53
|
+
namespace :gem do
|
54
|
+
desc "Update the gemspec for GitHub's gem server"
|
55
|
+
task :github do
|
56
|
+
File.open("#{GitRemoteBranch::NAME}.gemspec", 'w'){|f| f.puts YAML::dump(spec) }
|
57
|
+
puts "gemspec generated here: #{GitRemoteBranch::NAME}.gemspec"
|
58
|
+
end
|
59
|
+
|
60
|
+
desc 'Upload gem to rubyforge.org'
|
61
|
+
task :rubyforge => :gem do
|
62
|
+
sh 'rubyforge login'
|
63
|
+
sh "rubyforge add_release grb grb '#{GitRemoteBranch::VERSION::STRING}' pkg/#{spec.full_name}.gem"
|
64
|
+
sh "rubyforge add_file grb grb #{GitRemoteBranch::VERSION::STRING} pkg/#{spec.full_name}.gem"
|
65
|
+
end
|
66
|
+
|
67
|
+
desc 'Install the gem built locally'
|
68
|
+
task :install => [:clean, :gem] do
|
69
|
+
sh "#{SUDO} gem install pkg/#{spec.full_name}.gem"
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "Uninstall version #{GitRemoteBranch::VERSION::STRING} of the gem"
|
73
|
+
task :uninstall do
|
74
|
+
sh "#{SUDO} gem uninstall -v #{GitRemoteBranch::VERSION::STRING} -x #{GitRemoteBranch::NAME}"
|
75
|
+
end
|
76
|
+
|
77
|
+
if WINDOWS
|
78
|
+
win_spec = spec.dup
|
79
|
+
win_spec.platform = Gem::Platform::CURRENT
|
80
|
+
win_spec.add_dependency( 'win32console', '~> 1.1' ) # Missing dependency in the 'colored' gem
|
81
|
+
|
82
|
+
desc "Generate the Windows version of the gem"
|
83
|
+
namespace :windows do
|
84
|
+
Rake::GemPackageTask.new(win_spec) do |p|
|
85
|
+
p.gem_spec = win_spec
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/tasks/rdoc.rake
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rake/rdoctask'
|
2
|
+
|
3
|
+
desc 'Generate rdoc documentation'
|
4
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
5
|
+
rdoc.rdoc_dir = 'rdoc'
|
6
|
+
rdoc.title = GitRemoteBranch::NAME
|
7
|
+
rdoc.rdoc_files.include('README.rdoc')
|
8
|
+
end
|
9
|
+
|
10
|
+
namespace :rdoc do
|
11
|
+
desc 'Upload documentation to rubyforge'
|
12
|
+
task :upload => :rdoc do
|
13
|
+
sh "scp -r #{GRB_ROOT}/rdoc/* webmat@rubyforge.org:/var/www/gforge-projects/grb/"
|
14
|
+
end
|
15
|
+
end
|
data/tasks/test.rake
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
desc "Run all tests"
|
4
|
+
task :test => ["test:unit", "test:functional"]
|
5
|
+
|
6
|
+
namespace :test do
|
7
|
+
desc "Run functional tests"
|
8
|
+
Rake::TestTask.new(:functional) do |t|
|
9
|
+
t.pattern = 'test/functional/**/*_test.rb'
|
10
|
+
t.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Run unit tests"
|
14
|
+
Rake::TestTask.new(:unit) do |t|
|
15
|
+
t.pattern = 'test/unit/**/*_test.rb'
|
16
|
+
t.verbose = true
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,188 @@
|
|
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" do
|
24
|
+
setup do
|
25
|
+
in_directory_for :local2
|
26
|
+
end
|
27
|
+
|
28
|
+
context "not already having a branch of the same name" do
|
29
|
+
setup do
|
30
|
+
@output = run_grb_with 'track new_branch'
|
31
|
+
end
|
32
|
+
|
33
|
+
should_have_branch 'new_branch', :local, :remote
|
34
|
+
|
35
|
+
should "use the branch --track command" do
|
36
|
+
assert_match %r{branch --track}, @output
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "having a branch of the same name" do
|
41
|
+
setup do
|
42
|
+
execute "git branch new_branch"
|
43
|
+
@output = run_grb_with 'track new_branch'
|
44
|
+
end
|
45
|
+
|
46
|
+
should_have_branch 'new_branch', :local, :remote
|
47
|
+
|
48
|
+
should "use git config to connect the branches" do
|
49
|
+
assert_match %r{git\sconfig}, @output
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "then deleting the branch" do
|
55
|
+
setup do
|
56
|
+
run_grb_with 'delete new_branch'
|
57
|
+
end
|
58
|
+
|
59
|
+
should_not_have_branch 'new_branch', :local, :remote
|
60
|
+
|
61
|
+
context "the remote repository" do
|
62
|
+
setup do
|
63
|
+
in_directory_for :remote
|
64
|
+
end
|
65
|
+
|
66
|
+
should_not_have_branch 'new_branch', :local
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "renaming the branch" do
|
71
|
+
setup do
|
72
|
+
in_directory_for :local1
|
73
|
+
in_branch :new_branch
|
74
|
+
run_grb_with 'rename renamed_branch'
|
75
|
+
end
|
76
|
+
|
77
|
+
should_not_have_branch 'new_branch', :local, :remote
|
78
|
+
should_have_branch 'renamed_branch', :local, :remote
|
79
|
+
|
80
|
+
context "the remote repository" do
|
81
|
+
setup do
|
82
|
+
in_directory_for :remote
|
83
|
+
end
|
84
|
+
|
85
|
+
should_not_have_branch 'new_branch', :local
|
86
|
+
should_have_branch 'renamed_branch', :local
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "having a local only branch" do
|
92
|
+
setup do
|
93
|
+
in_directory_for :local1
|
94
|
+
execute "git branch my_branch"
|
95
|
+
end
|
96
|
+
|
97
|
+
should_have_branch 'my_branch', :local #Sanity check
|
98
|
+
|
99
|
+
context "remotizing the branch" do
|
100
|
+
setup do
|
101
|
+
run_grb_with 'publish my_branch'
|
102
|
+
end
|
103
|
+
|
104
|
+
should_have_branch 'my_branch', :remote
|
105
|
+
|
106
|
+
context "the remote repository" do
|
107
|
+
setup do
|
108
|
+
in_directory_for :remote
|
109
|
+
end
|
110
|
+
|
111
|
+
should_have_branch 'my_branch', :local
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "running grb with a detailed explain" do
|
117
|
+
setup do
|
118
|
+
in_directory_for :local1
|
119
|
+
@text = run_grb_with 'explain create teh_branch somewhere'
|
120
|
+
end
|
121
|
+
|
122
|
+
should "display the commands to run with the user-specified values, including current_branch" do
|
123
|
+
%w{master somewhere refs/heads/teh_branch}.each do |word|
|
124
|
+
assert_match(/#{word}/, @text)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
in_a_non_git_directory do
|
131
|
+
with_env_var :GRB_GIT, 'unknown_git_executable_name' do
|
132
|
+
context "when git is not in the path" do
|
133
|
+
setup do
|
134
|
+
@text = run_grb_with ''
|
135
|
+
end
|
136
|
+
should "complain about git not being in the path" do
|
137
|
+
assert_match %r{unknown_git_executable_name}, @text
|
138
|
+
assert_match %r{PATH}, @text
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context "displaying help" do
|
144
|
+
setup do
|
145
|
+
@text = run_grb_with 'help'
|
146
|
+
end
|
147
|
+
|
148
|
+
should "work" do
|
149
|
+
words_in_help = %w{create delete explain git_remote_branch}
|
150
|
+
words_in_help.each do |word|
|
151
|
+
assert_match(/#{word}/, @text)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
should "not complain" do
|
156
|
+
assert_no_match(/not a git repository/i, @text)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context "running grb with a generic explain" do
|
161
|
+
setup do
|
162
|
+
@text = run_grb_with 'explain create'
|
163
|
+
end
|
164
|
+
|
165
|
+
should "display the commands to run with dummy values filled in" do
|
166
|
+
#Not sure if this will turn out to be too precise to my liking...
|
167
|
+
generic_words_in_explain_create = %w{
|
168
|
+
origin current_branch refs/heads/branch_to_create
|
169
|
+
git push fetch checkout}
|
170
|
+
generic_words_in_explain_create.each do |word|
|
171
|
+
assert_match(/#{word}/, @text)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context "running grb with a detailed explain" do
|
177
|
+
setup do
|
178
|
+
@text = run_grb_with 'explain create teh_branch somewhere'
|
179
|
+
end
|
180
|
+
|
181
|
+
should "display the commands to run with the user-specified values (except for current_branch)" do
|
182
|
+
%w{somewhere current_branch refs/heads/teh_branch}.each do |word|
|
183
|
+
assert_match(/#{word}/, @text)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
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
|
+
|