hitch 0.5.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,18 +1,27 @@
1
+ require 'spec/rake/spectask'
2
+
3
+ task :default => :spec
4
+
5
+ desc "Run specs"
6
+ Spec::Rake::SpecTask.new do |t|
7
+ t.spec_files = FileList['spec/**/*_spec.rb']
8
+ t.spec_opts = %w(-fs --color)
9
+ end
10
+
1
11
  begin
2
12
  require 'jeweler'
3
- require 'lib/hitch'
4
- require 'fileutils'
5
13
  Jeweler::Tasks.new do |gemspec|
6
14
  gemspec.name = %q{hitch}
7
- gemspec.version = Hitch::VERSION
15
+ gemspec.version = '0.6.0'
8
16
  gemspec.summary = %q{Hitch allows developers to be properly credited when Pair Programming and using Git.}
9
17
  gemspec.email = %q{rogelio@therubymug.com}
10
18
  gemspec.homepage = %q{http://github.com/therubymug/hitch}
11
19
  gemspec.has_rdoc = false
12
- gemspec.authors = ["Rogelio Samour", "Les Hill"]
20
+ gemspec.authors = ["Rogelio J. Samour"]
13
21
  gemspec.files = %w( README.rdoc Rakefile ) + Dir["{bin,lib}/**/*"].sort
14
22
  gemspec.extra_rdoc_files = ["README.rdoc"]
15
- gemspec.executables = ["hitch", "unhitch", "hitchrc"]
23
+ gemspec.executables = ["hitch"]
24
+ gemspec.add_development_dependency "rspec", ">= 1.3.0"
16
25
  gemspec.add_dependency('highline', '>= 1.5.0')
17
26
  end
18
27
  Jeweler::GemcutterTasks.new
data/bin/hitch CHANGED
@@ -1,9 +1,34 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rubygems'
4
3
  require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib hitch]))
5
- include Hitch
6
4
 
7
- if personal_info
8
- hitch
5
+ args = ARGV
6
+ options = []
7
+ opts = OptionParser.new do |opts|
8
+ opts.banner = "Usage: hitch [options] first_pair_username second_pair_username"
9
+ opts.separator ""
10
+ opts.separator "General options:"
11
+ opts.on("-s", "--setup", "Print out shell goodies") do
12
+ options = [:setup]
13
+ end
14
+ opts.on("-u", "--unhitch", "Clear pair information") do
15
+ options = [:unhitch]
16
+ end
17
+ opts.separator ""
18
+ opts.separator "Common options:"
19
+ opts.on_tail("-h", "--help", "Show this message") do
20
+ puts opts
21
+ exit
22
+ end
23
+ opts.on_tail("-v", "--version", "Show version") do
24
+ abort "hitch v#{Hitch.version}"
25
+ end
9
26
  end
27
+ if args.any?
28
+ opts.parse!(args)
29
+ options = [:export, args] if options.empty?
30
+ else
31
+ options = [:print_info]
32
+ end
33
+
34
+ Hitch.send(*options)
@@ -1,284 +1,134 @@
1
1
  require 'highline'
2
2
  require 'yaml'
3
- require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib hitch options]))
3
+
4
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib hitch author]))
5
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib hitch ui]))
4
6
 
5
7
  module Hitch
6
8
 
7
- # :stopdoc:
8
- VERSION = '0.5.3'
9
- LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
- PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
- # :startdoc:
9
+ VERSION = '0.6.0'
12
10
 
13
- # Returns the version string for the library.
14
- #
15
11
  def self.version
16
12
  VERSION
17
13
  end
18
14
 
19
- # Returns the library path for the module. If any arguments are given,
20
- # they will be joined to the end of the libray path using
21
- # <tt>File.join</tt>.
22
- #
23
- def self.libpath( *args )
24
- args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
25
- end
26
-
27
- # Returns the lpath for the module. If any arguments are given,
28
- # they will be joined to the end of the path using
29
- # <tt>File.join</tt>.
30
- #
31
- def self.path( *args )
32
- args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
- end
34
-
35
- # Utility method used to require all files ending in .rb that lie in the
36
- # directory below this file that has the same name as the filename passed
37
- # in. Optionally, a specific _directory_ name can be passed in such that
38
- # the _filename_ does not have to be equivalent to the directory.
39
- #
40
- def self.require_all_libs_relative_to( fname, dir = nil )
41
- dir ||= ::File.basename(fname, '.*')
42
- search_me = ::File.expand_path(
43
- ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
44
-
45
- Dir.glob(search_me).sort.each {|rb| require rb}
46
- end
47
-
48
- HighLine.track_eof = false
49
-
50
- def write_hitchrc
51
- personal_info['current_pair'] = current_pair
52
- File.open(hitchrc, File::CREAT|File::TRUNC|File::RDWR, 0644) do |out|
53
- YAML.dump(personal_info, out)
15
+ def self.print_info
16
+ if Hitch.pairing?
17
+ Hitch::UI.highline.say("#{Hitch.git_author_name} <#{Hitch.git_author_email}>")
54
18
  end
55
19
  end
56
20
 
57
- def hitchrc
58
- @hitchrc ||= File.expand_path("~/.hitchrc")
59
- end
60
-
61
- def personal_info
62
- if File.exists?(hitchrc)
63
- @personal_info ||= YAML::load_file(hitchrc)
64
- else
65
- @personal_info ||= {}
66
- end
21
+ def self.export(pairs)
22
+ Hitch.current_pair = pairs
23
+ write_export_file
24
+ print_info
67
25
  end
68
26
 
69
- def hitch_pairs
70
- @hitch_pairs ||= File.expand_path("~/.hitch_pairs")
27
+ def self.unhitch
28
+ Hitch.current_pair = []
29
+ write_export_file
71
30
  end
72
31
 
73
- def pairs
74
- if File.exists?(hitch_pairs)
75
- @pairs ||= YAML::load_file(hitch_pairs)
32
+ def self.author_command
33
+ if Hitch.pairing?
34
+ "export GIT_AUTHOR_NAME='#{Hitch.git_author_name}' GIT_AUTHOR_EMAIL='#{Hitch.git_author_email}'"
76
35
  else
77
- @pairs ||= {}
36
+ "unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL"
78
37
  end
79
38
  end
80
39
 
81
- def write_hitch_pairs
82
- File.open(hitch_pairs, File::CREAT|File::TRUNC|File::RDWR, 0644) do |out|
83
- YAML.dump(pairs, out)
84
- end
85
- end
86
-
87
- def ui
88
- @ui ||= HighLine.new
40
+ def self.group_email
41
+ config[:group_email] ||= Hitch::UI.prompt_for_group_email
89
42
  end
90
43
 
91
- def exporting_hitch_authors
92
- !!hitch_options.export_hitch_authors
44
+ def self.group_email=(email)
45
+ config[:group_email] = email
46
+ write_file
93
47
  end
94
48
 
95
- def write_hitch_authors
96
- File.open(File.expand_path('~/.hitch_export_authors'), "w") do |f|
97
- f.puts "# "
98
- f.puts "export GIT_AUTHOR_NAME='#{hitch_name}'"
99
- f.puts "export GIT_AUTHOR_EMAIL='#{hitch_email}'"
100
- end
49
+ def self.current_pair
50
+ config[:current_pair] ||= []
101
51
  end
102
52
 
103
- def write_gitconfig
104
- clean_gitconfig
105
- File.open(hitch_options.current_gitconfig, "a+") do |f|
106
- f.puts "# start - lines added by hitch #"
107
- f.puts "[user]"
108
- f.puts "\tname = '#{hitch_name}'"
109
- f.puts "\temail = #{hitch_email}"
110
- f.puts "# end - lines added by hitch #"
53
+ def self.current_pair=(pairs)
54
+ config[:current_pair] = []
55
+ pairs.each do |author|
56
+ if Hitch::Author.find(author)
57
+ config[:current_pair] << author
58
+ else
59
+ if new_author = Hitch::UI.prompt_for_pair(author)
60
+ config[:current_pair] << author
61
+ end
62
+ end
111
63
  end
64
+ write_file
112
65
  end
113
66
 
114
- def add_pair(git_name)
115
- current_pair << git_name
116
- current_pair.sort!
117
- current_pair.uniq!
67
+ def self.git_author_name
68
+ current_pair.sort.map {|pair| Hitch::Author.find(pair)}.join(' and ')
118
69
  end
119
70
 
120
- def current_pair
121
- @current_pair ||= (personal_info['current_pair'] or [])
71
+ def self.git_author_email
72
+ "#{group_prefix}+#{current_pair.sort.join('+')}@#{group_domain}"
122
73
  end
123
74
 
124
- def hitch_name
125
- my_pairs_and_i.map {|github, name| name}.join(' and ')
75
+ def self.group_prefix
76
+ group_email.split('@').first
126
77
  end
127
78
 
128
- def hitch_email
129
- "#{group_prefix}+#{my_pairs_and_i.map{|github, name| github}.join('+')}@#{group_domain}"
79
+ def self.group_domain
80
+ group_email.split('@').last
130
81
  end
131
82
 
132
- def my_pairs_and_i
133
- and_i = current_pair.map {|github| [github, pairs[github]]}
134
- and_i.sort_by {|github, name| github }
135
- end
136
-
137
- def group_prefix
138
- personal_info['group_email'].split('@').first
139
- end
83
+ def self.setup
84
+ Hitch::UI.highline.say <<-stp
140
85
 
141
- def group_domain
142
- personal_info['group_email'].split('@').last
143
- end
144
-
145
- def clean_hitch_authors
146
- authors_file = File.expand_path '~/.hitch_export_authors'
147
- File.open(authors_file, 'w') do |f|
148
- f.puts "unset GIT_AUTHOR_NAME"
149
- f.puts "unset GIT_AUTHOR_EMAIL"
150
- end
151
- end
86
+ # Add the following to your ~/.bashrc or ~/.zshrc
87
+ hitch() {
88
+ command hitch "$@"
89
+ if [[ -s "$HOME/.hitch_export_authors" ]] ; then source "$HOME/.hitch_export_authors" ; fi
90
+ }
91
+ alias unhitch='hitch -u'
92
+ # Uncomment to persist pair info between terminal instances
93
+ # hitch
152
94
 
153
- def clean_gitconfig(opts={:print => false})
154
- config_file = hitch_options.current_gitconfig
155
- ui.say " Clearing hitch info in: #{config_file}" if opts[:print]
156
- body = File.read(config_file)
157
- body.gsub!(/# start - lines added by hitch #\n.*?\n# end - lines added by hitch #\n/m, '')
158
- File.open(config_file + ".tmp", 'w') {|f| f.write(body)}
159
- File.rename(config_file + ".tmp", config_file)
95
+ stp
160
96
  end
161
97
 
162
- def prep_hitch_authors
163
- if pairing?
164
- write_hitch_authors
165
- else
166
- clean_hitch_authors
98
+ def self.write_file
99
+ File.open(hitchrc, File::CREAT|File::TRUNC|File::RDWR, 0644) do |out|
100
+ YAML.dump(config, out)
167
101
  end
168
102
  end
169
103
 
170
- def prep_gitconfig
171
- if pairing?
172
- write_gitconfig
173
- else
174
- clean_gitconfig
175
- end
176
- end
104
+ private
177
105
 
178
- def unhitch
179
- if personal_info
180
- clear_pair_info
181
- write_hitchrc
182
- if exporting_hitch_authors
183
- clean_hitch_authors
184
- else
185
- clean_gitconfig(:print => true)
186
- end
187
- print_current_status
188
- end
106
+ def self.config
107
+ @config ||= get_config
189
108
  end
190
109
 
191
- def print_current_status
192
- if pairing?
193
- ui.say " Currently pairing with #{current_pair.join(' ')}."
194
- else
195
- ui.say " Currently coding solo."
110
+ def self.get_config
111
+ if File.exists?(hitchrc)
112
+ yamlized = YAML::load_file(hitchrc)
113
+ return yamlized if yamlized.kind_of?(Hash)
196
114
  end
115
+ return {}
197
116
  end
198
117
 
199
- def print_version
200
- ui.say "hitch v#{Hitch.version}"
201
- end
202
-
203
- def clear_pair_info
204
- personal_info['current_pair'] = []
205
- end
206
-
207
- def pairing?
208
- return false if personal_info.empty?
209
- return false if personal_info['current_pair'].nil? || personal_info['current_pair'].length.zero?
210
- return false if personal_info['current_pair'].length < 2
211
- true
118
+ def self.hitchrc
119
+ File.expand_path('~/.hitchrc')
212
120
  end
213
121
 
214
- def existing_pair?(pair)
215
- pairs.any? {|github, name| github == pair}
122
+ def self.hitch_export_authors
123
+ File.expand_path('~/.hitch_export_authors')
216
124
  end
217
125
 
218
- def hitch_options
219
- @hitch_options ||= Options.parse(ARGV)
126
+ def self.pairing?
127
+ current_pair.any?
220
128
  end
221
129
 
222
- def hitch
223
- case hitch_options.action
224
- when "manage_hitchrc"
225
- manage_hitchrc
226
- when "unhitch"
227
- unhitch
228
- when "hitch"
229
- if ARGV.any? && ARGV.size >= 2
230
- potential_pairs = ARGV
231
- save_pairs = false
232
- clear_pair_info
233
-
234
- potential_pairs.each do |pair|
235
- unless existing_pair?(pair)
236
- ui.say("I don't know who #{pair} is.")
237
- if ui.agree("Do you want to add #{pair} to ~/.hitch_pairs? ", true)
238
- pairs[pair] = ui.ask("What is #{pair}'s full name?") do |q|
239
- q.validate = /\A[-(\w|.,)+\s?]+\Z/
240
- end
241
- add_pair(pair)
242
- save_pairs ||= true
243
- else
244
- ui.say("Ignoring #{pair}.")
245
- end
246
- else
247
- add_pair(pair)
248
- end
249
- end
250
- write_hitchrc
251
- write_hitch_pairs if save_pairs
252
- if exporting_hitch_authors
253
- prep_hitch_authors
254
- else
255
- prep_gitconfig
256
- end
257
- else
258
- ui.say " Silly Rabbit! A pair is comprised of two." unless ARGV.size.zero?
259
- end
260
- print_current_status
261
- end
262
- end
263
-
264
- def manage_hitchrc
265
- begin
266
- unless File.exists?(hitchrc) and !ui.agree("Do you want to overwrite your #{ENV['HOME']}/.hitchrc file?", true)
267
- ui.say("Let's setup your #{ENV['HOME']}/.hitchrc file")
268
-
269
- personal_info['group_email'] = ui.ask("What is the group email? e.g. dev@hashrocket.com will become dev+therubymug+leshill@hashrocket.com") do |q|
270
- q.case = :down
271
- q.validate = /\A[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+\z/ # Simple email validation.
272
- end
273
-
274
- write_hitchrc
275
- end
276
- rescue EOFError # HighLine throws this if @input.eof?
277
- break
278
- end
279
-
280
- print_current_status
130
+ def self.write_export_file
131
+ File.open(hitch_export_authors, 'w'){|f| f.write(author_command) }
281
132
  end
282
- end # module Hitch
283
133
 
284
- Hitch.require_all_libs_relative_to(__FILE__)
134
+ end
@@ -0,0 +1,39 @@
1
+ module Hitch
2
+ class Author
3
+
4
+ def self.add(author_github, author_email)
5
+ unless find(author_github)
6
+ available_pairs[author_github] = author_email
7
+ end
8
+ end
9
+
10
+ def self.find(author_github)
11
+ available_pairs[author_github]
12
+ end
13
+
14
+ def self.write_file
15
+ File.open(hitch_pairs, File::CREAT|File::TRUNC|File::RDWR, 0644) do |out|
16
+ YAML.dump(available_pairs, out)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def self.hitch_pairs
23
+ File.expand_path("~/.hitch_pairs")
24
+ end
25
+
26
+ def self.available_pairs
27
+ @available_pairs ||= get_available_pairs
28
+ end
29
+
30
+ def self.get_available_pairs
31
+ if File.exists?(hitch_pairs)
32
+ yamlized = YAML::load_file(hitch_pairs)
33
+ return yamlized if yamlized.kind_of?(Hash)
34
+ end
35
+ return {}
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ HighLine.track_eof = false
2
+
3
+ module Hitch
4
+ class UI
5
+
6
+ def self.prompt_for_group_email
7
+ Hitch.group_email = highline.ask("What is the group email? e.g. dev@hashrocket.com will become dev+therubymug+leshill@hashrocket.com") do |q|
8
+ q.case = :down
9
+ q.validate = /\A[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+\z/
10
+ end
11
+ end
12
+
13
+ def self.prompt_for_pair(new_author)
14
+ highline.say("I don't know who #{new_author} is.")
15
+ if highline.agree("Do you want to add #{new_author} to ~/.hitch_pairs?", true)
16
+ author_name = highline.ask("What is #{new_author}'s full name?") do |q|
17
+ q.validate = /\A[-(\w|.,)+\s?]+\Z/
18
+ end
19
+ Hitch::Author.add(new_author, author_name)
20
+ Hitch::Author.write_file
21
+ return new_author
22
+ else
23
+ highline.say("Ignoring #{new_author}.")
24
+ end
25
+ return nil
26
+ end
27
+
28
+ private
29
+
30
+ def self.highline
31
+ @highline ||= HighLine.new
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ require 'yaml'
2
+ require 'highline'
3
+ require 'fileutils'
4
+ require 'tempfile'
5
+
6
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'hitch')
7
+
8
+ Spec::Runner.configure do |config|
9
+ config.before(:each) do
10
+ Hitch.stub(:hitchrc).and_return(Tempfile.new('hitchrc').path)
11
+ Hitch.stub(:hitch_export_authors).and_return(Tempfile.new('hitch_export_authors').path)
12
+ Hitch::Author.stub(:hitch_pairs).and_return(Tempfile.new('hitch_pairs').path)
13
+ end
14
+ end
@@ -0,0 +1,57 @@
1
+ require 'helper'
2
+
3
+ describe Hitch::Author do
4
+
5
+ let(:base_pairs) do
6
+ {
7
+ 'bender' => 'Bender Bending Rodriguez',
8
+ 'fry' => 'Phillip J. Fry',
9
+ 'leela' => 'Turanga Leela'
10
+ }
11
+ end
12
+
13
+ before { Hitch::Author.stub(:available_pairs).and_return(base_pairs) }
14
+
15
+ describe ".write_file" do
16
+ it "writes the contents of Hitch::Author.available_pairs to the hitch_pairs file" do
17
+ YAML.should_receive(:dump)
18
+ Hitch::Author.write_file
19
+ end
20
+ end
21
+
22
+ describe ".add" do
23
+
24
+ before { Hitch::Author.stub(:available_pairs).and_return({}) }
25
+
26
+ context "when the author is not present" do
27
+ it "adds the author to Hitch::Author.available_pairs" do
28
+ Hitch::Author.add("therubymug", "Rogelio J. Samour")
29
+ Hitch::Author.available_pairs.should == {"therubymug" => "Rogelio J. Samour"}
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ describe ".find" do
36
+
37
+ context "when the author is present" do
38
+
39
+ before do
40
+ Hitch::Author.stub(:available_pairs).and_return({"therubymug" => "Rogelio J. Samour"})
41
+ end
42
+
43
+ it "and_return the full name" do
44
+ Hitch::Author.find("therubymug").should == "Rogelio J. Samour"
45
+ end
46
+
47
+ end
48
+
49
+ context "when the author is not present" do
50
+ it "and_return nil" do
51
+ Hitch::Author.find("nobody").should be_nil
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,78 @@
1
+ require 'helper'
2
+
3
+ describe Hitch::UI do
4
+
5
+ describe '.prompt_for_group_email' do
6
+
7
+ it 'prompts for group email' do
8
+ Hitch::UI.highline.should_receive(:ask).with("What is the group email? e.g. dev@hashrocket.com will become dev+therubymug+leshill@hashrocket.com")
9
+ Hitch::UI.prompt_for_group_email
10
+ end
11
+
12
+ it 'returns the given group email' do
13
+ Hitch::UI.highline.stub(:ask).with("What is the group email? e.g. dev@hashrocket.com will become dev+therubymug+leshill@hashrocket.com").and_return('dev@hashrocket.com')
14
+ Hitch::UI.prompt_for_group_email.should == 'dev@hashrocket.com'
15
+ end
16
+
17
+ it 'sets Hitch.group_email' do
18
+ Hitch.should_receive('group_email=').with('dev@hashrocket.com')
19
+ Hitch::UI.highline.stub(:ask).with("What is the group email? e.g. dev@hashrocket.com will become dev+therubymug+leshill@hashrocket.com").and_return('dev@hashrocket.com')
20
+ Hitch::UI.prompt_for_group_email
21
+ end
22
+
23
+ end
24
+
25
+ describe '.prompt_for_pair' do
26
+
27
+ let(:new_author) { 'leela' }
28
+ let(:new_author_name) { 'Turanga Leela' }
29
+
30
+ before do
31
+ Hitch::UI.highline.stub(:ask).and_return(new_author_name)
32
+ Hitch::UI.highline.stub(:say)
33
+ end
34
+
35
+ it 'states that the new pair is not in the hitch_pairs file' do
36
+ Hitch::UI.highline.should_receive(:say).with("I don't know who #{new_author} is.")
37
+ Hitch::UI.prompt_for_pair(new_author)
38
+ end
39
+
40
+ it 'prompts for pair' do
41
+ Hitch::UI.highline.should_receive(:agree).with("Do you want to add #{new_author} to ~/.hitch_pairs?", true)
42
+ Hitch::UI.prompt_for_pair(new_author)
43
+ end
44
+
45
+ context 'when user does not agree to add new author' do
46
+ it "states it's ignoring the author" do
47
+ Hitch::UI.highline.stub(:agree).and_return(false)
48
+ Hitch::UI.highline.should_receive(:say).with("Ignoring #{new_author}.")
49
+ Hitch::UI.prompt_for_pair(new_author)
50
+ end
51
+ end
52
+
53
+ context 'when user agrees to add new author' do
54
+
55
+ before do
56
+ Hitch::UI.highline.stub(:agree).and_return(true)
57
+ end
58
+
59
+ it "asks for the new author's name" do
60
+ Hitch::UI.highline.should_receive(:ask).with("What is #{new_author}'s full name?")
61
+ Hitch::UI.prompt_for_pair(new_author)
62
+ end
63
+
64
+ it "adds the new author" do
65
+ Hitch::Author.should_receive(:add).with(new_author, new_author_name)
66
+ Hitch::UI.prompt_for_pair(new_author)
67
+ end
68
+
69
+ it "writes the ~/.hitch_pairs file" do
70
+ Hitch::Author.should_receive(:write_file)
71
+ Hitch::UI.prompt_for_pair(new_author)
72
+ end
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end
@@ -0,0 +1,205 @@
1
+ require 'helper'
2
+
3
+ describe Hitch do
4
+
5
+ let(:hitch_pairs) {{'leela' => 'Turanga Leela', 'fry' => 'Philip J. Fry'}}
6
+
7
+ let(:hitch_config) do
8
+ { :group_email => 'dev@hashrocket.com',
9
+ :current_pair => ['leela', 'fry'] }
10
+ end
11
+
12
+ before do
13
+ Hitch.stub(:config).and_return(hitch_config)
14
+ Hitch::Author.stub(:available_pairs).and_return(hitch_pairs)
15
+ end
16
+
17
+ describe '.author_command' do
18
+
19
+ context 'when pairing' do
20
+ it 'returns the export shell command for GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL' do
21
+ Hitch.current_pair = ['leela', 'fry']
22
+ Hitch.author_command.should == "export GIT_AUTHOR_NAME='Philip J. Fry and Turanga Leela' GIT_AUTHOR_EMAIL='dev+fry+leela@hashrocket.com'"
23
+ end
24
+ end
25
+
26
+ context 'when not pairing' do
27
+ it 'returns the unset shell command for GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL' do
28
+ Hitch.current_pair = []
29
+ Hitch.author_command.should == "unset GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL"
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ describe '.unhitch' do
36
+
37
+ let(:pairs) { ['fry', 'leela'] }
38
+
39
+ it 'sets the current pair to an empty array' do
40
+ Hitch.should_receive(:current_pair=).with([])
41
+ Hitch.unhitch
42
+ end
43
+
44
+ it 'writes the export file' do
45
+ Hitch.should_receive(:write_export_file)
46
+ Hitch.unhitch
47
+ end
48
+
49
+ end
50
+
51
+ describe '.print_info' do
52
+
53
+ context 'when pairing' do
54
+ it 'returns the pair name and email being used' do
55
+ Hitch::UI.highline.should_receive(:say).with("Philip J. Fry and Turanga Leela <dev+fry+leela@hashrocket.com>")
56
+ Hitch.current_pair = ['leela', 'fry']
57
+ Hitch.print_info
58
+ end
59
+ end
60
+
61
+ context 'when not pairing' do
62
+ it 'returns nothing' do
63
+ Hitch.current_pair = []
64
+ Hitch.print_info.should be_nil
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ describe '.export' do
71
+
72
+ let(:pairs) { ['fry', 'leela'] }
73
+
74
+ before do
75
+ Hitch.stub(:print_info)
76
+ end
77
+
78
+ it 'sets the current pair' do
79
+ Hitch.should_receive(:current_pair=).with(pairs)
80
+ Hitch.export(pairs)
81
+ end
82
+
83
+ it 'writes the export file' do
84
+ Hitch.should_receive(:write_export_file)
85
+ Hitch.export(pairs)
86
+ end
87
+
88
+ it 'prints out pair info' do
89
+ Hitch.should_receive(:print_info)
90
+ Hitch.export(pairs)
91
+ end
92
+
93
+ end
94
+
95
+ describe '.current_pair=' do
96
+
97
+ before { Hitch.stub(:write_file) }
98
+
99
+ it 'writes the hitchrc file' do
100
+ Hitch.should_receive(:write_file)
101
+ Hitch.current_pair = ['leela', 'fry']
102
+ end
103
+
104
+ context 'when there are no new authors' do
105
+ it 'sets the current pair with the authors given' do
106
+ Hitch.current_pair = ['leela', 'fry']
107
+ Hitch.current_pair.should == ['leela', 'fry']
108
+ end
109
+ end
110
+
111
+ context 'when there are new authors' do
112
+
113
+ let(:new_author) { 'therubymug' }
114
+
115
+ it "prompts for the new author's info" do
116
+ Hitch::UI.should_receive(:prompt_for_pair).with(new_author)
117
+ Hitch.current_pair = [new_author, 'fry']
118
+ end
119
+
120
+ it 'adds the new author to current pair' do
121
+ Hitch::UI.stub(:prompt_for_pair).and_return(new_author)
122
+ Hitch.current_pair = [new_author, 'fry']
123
+ Hitch.current_pair.should == [new_author, 'fry']
124
+ end
125
+
126
+ end
127
+
128
+ end
129
+
130
+ describe '.current_pair' do
131
+ it 'returns an array of Github usernames' do
132
+ Hitch.stub(:config).and_return(hitch_config)
133
+ Hitch.current_pair.should == ['leela', 'fry']
134
+ end
135
+ end
136
+
137
+ describe '.group_email' do
138
+
139
+ context 'when absent from Hitch.config' do
140
+ before { Hitch.stub(:config).and_return({}) }
141
+ it 'prompts the user for it' do
142
+ Hitch::UI.should_receive(:prompt_for_group_email)
143
+ Hitch.group_email
144
+ end
145
+ end
146
+
147
+ context 'when present in Hitch.config' do
148
+ it 'returns the value' do
149
+ Hitch.group_email.should == 'dev@hashrocket.com'
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ describe '.group_email=' do
156
+
157
+ before { Hitch.stub(:write_file) }
158
+
159
+ it 'writes the hitchrc file' do
160
+ Hitch.should_receive(:write_file)
161
+ Hitch.group_email = 'dev@hashrocket.com'
162
+ end
163
+
164
+ it 'sets the current pair with the authors given' do
165
+ Hitch.group_email = 'dev@hashrocket.com'
166
+ Hitch.group_email.should == 'dev@hashrocket.com'
167
+ end
168
+
169
+ end
170
+
171
+ describe '.group_prefix' do
172
+ it 'returns the user portion of the group email' do
173
+ Hitch.group_prefix.should == 'dev'
174
+ end
175
+ end
176
+
177
+ describe '.group_domain' do
178
+ it 'returns the user portion of the group email' do
179
+ Hitch.group_domain.should == 'hashrocket.com'
180
+ end
181
+ end
182
+
183
+ describe '.git_author_name' do
184
+ it 'returns all author names joined by an "and" sorted alphabetically' do
185
+ Hitch.git_author_name.should == 'Philip J. Fry and Turanga Leela'
186
+ end
187
+ end
188
+
189
+ describe '.git_author_email' do
190
+ it 'returns all author github names coalesced into the group email' do
191
+ Hitch.git_author_email.should == 'dev+fry+leela@hashrocket.com'
192
+ end
193
+ end
194
+
195
+ describe ".write_file" do
196
+ it "writes the contents of Hitch.config to the hitchrc file" do
197
+ YAML.should_receive(:dump)
198
+ Hitch.write_file
199
+ end
200
+ end
201
+
202
+ describe '.command' do
203
+ end
204
+
205
+ end
metadata CHANGED
@@ -1,56 +1,73 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hitch
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 7
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
- - 5
8
- - 3
9
- version: 0.5.3
8
+ - 6
9
+ - 0
10
+ version: 0.6.0
10
11
  platform: ruby
11
12
  authors:
12
- - Rogelio Samour
13
- - Les Hill
13
+ - Rogelio J. Samour
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-03-02 00:00:00 -05:00
19
- default_executable:
18
+ date: 2010-08-24 00:00:00 -04:00
19
+ default_executable: hitch
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: highline
22
+ name: rspec
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
25
26
  requirements:
26
27
  - - ">="
27
28
  - !ruby/object:Gem::Version
29
+ hash: 27
30
+ segments:
31
+ - 1
32
+ - 3
33
+ - 0
34
+ version: 1.3.0
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: highline
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
28
46
  segments:
29
47
  - 1
30
48
  - 5
31
49
  - 0
32
50
  version: 1.5.0
33
51
  type: :runtime
34
- version_requirements: *id001
52
+ version_requirements: *id002
35
53
  description:
36
54
  email: rogelio@therubymug.com
37
55
  executables:
38
56
  - hitch
39
- - unhitch
40
- - hitchrc
41
57
  extensions: []
42
58
 
43
- extra_rdoc_files:
44
- - README.rdoc
59
+ extra_rdoc_files: []
60
+
45
61
  files:
46
- - README.rdoc
47
62
  - Rakefile
48
63
  - bin/hitch
49
- - bin/hitchrc
50
- - bin/hitchstatus
51
- - bin/unhitch
52
64
  - lib/hitch.rb
53
- - lib/hitch/options.rb
65
+ - lib/hitch/author.rb
66
+ - lib/hitch/ui.rb
67
+ - spec/helper.rb
68
+ - spec/hitch/author_spec.rb
69
+ - spec/hitch/ui_spec.rb
70
+ - spec/hitch_spec.rb
54
71
  has_rdoc: true
55
72
  homepage: http://github.com/therubymug/hitch
56
73
  licenses: []
@@ -61,25 +78,32 @@ rdoc_options:
61
78
  require_paths:
62
79
  - lib
63
80
  required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
64
82
  requirements:
65
83
  - - ">="
66
84
  - !ruby/object:Gem::Version
85
+ hash: 3
67
86
  segments:
68
87
  - 0
69
88
  version: "0"
70
89
  required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
71
91
  requirements:
72
92
  - - ">="
73
93
  - !ruby/object:Gem::Version
94
+ hash: 3
74
95
  segments:
75
96
  - 0
76
97
  version: "0"
77
98
  requirements: []
78
99
 
79
100
  rubyforge_project:
80
- rubygems_version: 1.3.6
101
+ rubygems_version: 1.3.7
81
102
  signing_key:
82
103
  specification_version: 3
83
104
  summary: Hitch allows developers to be properly credited when Pair Programming and using Git.
84
- test_files: []
85
-
105
+ test_files:
106
+ - spec/helper.rb
107
+ - spec/hitch/author_spec.rb
108
+ - spec/hitch/ui_spec.rb
109
+ - spec/hitch_spec.rb
@@ -1,76 +0,0 @@
1
- = hitch
2
- by Rogelio J. Samour
3
- http://therubymug.com
4
-
5
- == DESCRIPTION:
6
-
7
- Hitch allows developers to be properly credited when Pair Programming and using Git.
8
-
9
- == FEATURES:
10
-
11
- * Persists pair(s) between different terminal instances.
12
- * Creates a unique email address for the pair. (e.g. dev+leshill+therubymug@hashrocket.com) This provides the ability to create a Gravatar for the pair.
13
-
14
- == SYNOPSIS:
15
-
16
- - First, create your hitchrc by running:
17
- - hitch -m
18
- - For therubymug and leshill to pair in the current project:
19
- - hitch leshill therubymug
20
- - or globally:
21
- - hitch -g leshill therubymug
22
- - To clear pair info (for the local project):
23
- - hitch -u
24
- - To clear pair info in the global file:
25
- - hitch -u -g
26
- - For a complete list of features:
27
- - hitch -h
28
- - Creating a Gravatar for your pair:
29
- - Once I've hitched with my pair. (e.g. hitch leshill) I have now created a unique email: dev+leshill+therubymug@hashrocket.com
30
- - Then, I go to gravatar.com. Add an image to that particular email address and I'm done.
31
- - If you want to allow different committer vs author, then:
32
- - unhitch (unhitch the current project)
33
- - unhitch -g (globally unhitch)
34
- - add the following aliases to your .bashrc:
35
- alias hitch='hitch -p -g'
36
- alias unhitch='unhitch -p -g'
37
- alias git='. ~/.hitch_export_authors && git'
38
-
39
- == REQUIREMENTS:
40
-
41
- * Git, HighLine
42
-
43
- == INSTALL:
44
-
45
- * sudo gem install therubymug-hitch
46
-
47
- == ACKNOWLEDGEMENTS:
48
-
49
- * Les Hill
50
- * Tim Pope
51
- * Bodaniel Jeanes
52
-
53
- == LICENSE:
54
-
55
- (The MIT License)
56
-
57
- Copyright (c) 2009 Rogelio J. Samour
58
-
59
- Permission is hereby granted, free of charge, to any person obtaining
60
- a copy of this software and associated documentation files (the
61
- 'Software'), to deal in the Software without restriction, including
62
- without limitation the rights to use, copy, modify, merge, publish,
63
- distribute, sublicense, and/or sell copies of the Software, and to
64
- permit persons to whom the Software is furnished to do so, subject to
65
- the following conditions:
66
-
67
- The above copyright notice and this permission notice shall be
68
- included in all copies or substantial portions of the Software.
69
-
70
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
71
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
72
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
73
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
74
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
75
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
76
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
- require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib hitch]))
5
- include Hitch
6
-
7
- manage_hitchrc
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
-
5
- require 'yaml'
6
- yaml = YAML.load(File.read(File.expand_path('~/.hitchrc')))
7
- pairs = yaml['current_pair']
8
- print pairs.join(':') if pairs
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'rubygems'
4
- require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib hitch]))
5
- include Hitch
6
-
7
- unhitch
@@ -1,71 +0,0 @@
1
- require 'optparse'
2
- require 'optparse/time'
3
- require 'ostruct'
4
-
5
- module Hitch
6
-
7
- class Options
8
-
9
- def self.parse(args)
10
- options = OpenStruct.new
11
- options.action = "hitch"
12
-
13
- opts = OptionParser.new do |opts|
14
- opts.banner = "Usage: hitch [options] first_pair_username second_pair_username"
15
- opts.separator ""
16
- opts.separator "Hitch defaults to the current project's .git/config"
17
- opts.separator ""
18
- opts.separator "General options:"
19
-
20
- opts.on('-p', '--preserve_gitconfig', 'Preserves your ~/.gitconfig and .git/config files. Uses ~/.hitch_export_authors instead') do
21
- options.export_hitch_authors = true
22
- end
23
-
24
- opts.on("-g", "--global", "Modifies your global ~/.gitconfig") do
25
- options.current_gitconfig = File.expand_path("~/.gitconfig")
26
- end
27
-
28
- opts.on("-m", "--manage-hitchrc", "Creates or manages your personal information into ~/.hitchrc") do
29
- if options.action.empty? || options.action == "hitch"
30
- options.action = "manage_hitchrc"
31
- else
32
- abort "You can only perform one action at a time. hitch -h for more info."
33
- end
34
- end
35
-
36
- opts.on("-u", "--unhitch", "Clear pair information") do
37
- if options.action.empty? || options.action == "hitch"
38
- options.action = "unhitch"
39
- else
40
- abort "You can only perform one action at a time. hitch -h for more info."
41
- end
42
- end
43
-
44
- opts.separator ""
45
- opts.separator "Common options:"
46
-
47
- opts.on_tail("-h", "--help", "Show this message") do
48
- puts opts
49
- exit
50
- end
51
-
52
- opts.on_tail("-v", "--version", "Show version") do
53
- abort "hitch v#{Hitch.version}"
54
- end
55
- end
56
-
57
- opts.parse!(args)
58
-
59
- if options.current_gitconfig.nil?
60
- options.current_gitconfig = File.expand_path(File.join(Dir.pwd, ".git", "config"))
61
- end
62
-
63
- unless File.exists?(options.current_gitconfig)
64
- abort "Config File: #{options.current_gitconfig} does not exist. hitch -h for more info."
65
- end
66
-
67
- options
68
- end
69
-
70
- end
71
- end