mavenlink-git-scripts 1.5.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.
@@ -0,0 +1,3 @@
1
+ module PivotalGitScripts
2
+ VERSION = "1.5.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
4
+
5
+ require 'pivotal_git_scripts/version'
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = 'mavenlink-git-scripts'
9
+ gem.version = PivotalGitScripts::VERSION
10
+ gem.authors = ['Pivotal Labs, Mavenlink']
11
+ gem.email = ['gems@pivotallabs.com, dev@mavenlink.com']
12
+ gem.homepage = 'http://github.com/jrolfs/git-scripts'
13
+ gem.summary = 'Developer Git workflow convenience scripts'
14
+ gem.description = 'These scripts are helpers for managing developer workflow when using Git repos hosted on GitHub.'
15
+
16
+ gem.rubyforge_project = 'pivotal_git_scripts'
17
+
18
+ gem.files = `git ls-files`.split("\n")
19
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ gem.require_paths = ['lib']
22
+ gem.license = 'MIT'
23
+
24
+ gem.add_development_dependency 'rake'
25
+ gem.add_development_dependency 'bundler'
26
+ gem.add_development_dependency 'rspec'
27
+ gem.add_development_dependency 'unindent'
28
+ gem.add_development_dependency 'gem-release'
29
+ end
@@ -0,0 +1,505 @@
1
+ require "unindent"
2
+
3
+ describe "CLI" do
4
+ before :all do
5
+ # use local scripts
6
+ ENV["PATH"] = "#{File.join(File.dirname(__FILE__),"..","bin")}:#{ENV["PATH"]}"
7
+ end
8
+
9
+ def run(command, options={})
10
+ output = `#{command}`
11
+ return output if $?.success?
12
+ return output if options[:fail]
13
+
14
+ message = "Unable to run #{command.inspect} in #{Dir.pwd}.\n#{output}"
15
+ warn "ERROR: #{message}"
16
+ raise message
17
+ end
18
+
19
+ def write(file, content)
20
+ File.open(file, 'w'){|f| f.write content }
21
+ end
22
+
23
+ around do |example|
24
+ dir = "spec/tmp"
25
+ run "rm -rf #{dir}"
26
+ run "mkdir #{dir}"
27
+
28
+ # use fake home for .ssh hacks
29
+ run "mkdir #{dir}/home"
30
+ ENV["HOME"] = File.absolute_path("#{dir}/home")
31
+
32
+ Dir.chdir dir do
33
+ run "touch a"
34
+ run "git init"
35
+ run "git add ."
36
+ run "git config user.email 'rspec-tests@example.com'"
37
+ run "git config user.name 'rspec test suite'"
38
+ run "git commit -am 'initial'"
39
+ run "git config --unset user.email"
40
+ run "git config --unset user.name"
41
+ example.run
42
+ end
43
+ end
44
+
45
+ describe "about" do
46
+ it "lists the user" do
47
+ run "git config user.name NAME"
48
+ run("git about").should =~ /git user:\s+NAME/
49
+ end
50
+
51
+ it "lists the user as NONE if there is none" do
52
+ run "git config user.name ''"
53
+ run("git about").should =~ /git user:\s+NONE/
54
+ end
55
+
56
+ it "lists the email" do
57
+ run "git config user.email EMAIL"
58
+ run("git about").should =~ /git email:\s+EMAIL/
59
+ end
60
+
61
+ it "lists the email as NONE if there is none" do
62
+ run "git config user.email ''"
63
+ run("git about").should =~ /git email:\s+NONE/
64
+ end
65
+
66
+ it "does not find a project" do
67
+ run("git about").should =~ /GitHub project:\s+NONE/
68
+ end
69
+
70
+ context "with github project" do
71
+ before do
72
+ run "mkdir home/.ssh"
73
+ run "touch home/.ssh/id_github_foo"
74
+ run "ln -s home/.ssh/id_github_foo home/.ssh/id_github_current"
75
+ end
76
+
77
+ it "finds a project" do
78
+ run("git about").should =~ /GitHub project:\s+foo/
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "pair" do
84
+ def expect_config(result, name, initials, email, options={})
85
+ global = "cd /tmp && " if options[:global]
86
+ run("#{global}git config user.name").should == "#{name}\n"
87
+ run("#{global}git config user.initials").should == "#{initials}\n"
88
+ run("#{global}git config user.email").should == "#{email}\n"
89
+
90
+ prefix = (options[:global] ? "global: " : "local: ")
91
+ result.should include "#{prefix}user.name #{name}"
92
+ result.should include "#{prefix}user.initials #{initials}"
93
+ result.should include "#{prefix}user.email #{email}"
94
+ end
95
+
96
+ def git_config_value(name, global = false)
97
+ global_prefix = "cd /tmp && " if global
98
+ `#{global_prefix}git config user.#{name}`
99
+ end
100
+
101
+ it "prints help" do
102
+ result = run "git-pair --help"
103
+ result.should include("Configures git authors when pair programming")
104
+ end
105
+
106
+ it "prints version" do
107
+ result = run "git pair --version"
108
+ result.should =~ /\d+\.\d+\.\d+/
109
+ end
110
+
111
+ context "with .pairs file" do
112
+ before do
113
+ write ".pairs", <<-YAML.unindent
114
+ pairs:
115
+ ab: Aa Bb
116
+ bc: Bb Cc
117
+ cd: Cc Dd
118
+
119
+ email:
120
+ prefix: the-pair
121
+ domain: the-host.com
122
+ YAML
123
+ end
124
+
125
+ describe "global" do
126
+ it "sets pairs globally when global: true is set" do
127
+ write ".pairs", File.read(".pairs") + "\nglobal: true"
128
+ result = run "git pair ab"
129
+ expect_config result, "Aa Bb", "ab", "the-pair+aa@the-host.com", :global => true
130
+ end
131
+
132
+ it "sets pairs globally when --global is given" do
133
+ result = run "git pair ab --global"
134
+ result.should include "global: user.name Aa Bb"
135
+ expect_config result, "Aa Bb", "ab", "the-pair+aa@the-host.com", :global => true
136
+ end
137
+
138
+ it "unsets global config when no argument is passed" do
139
+ run "git pair ab --global"
140
+ run "git pair ab"
141
+ result = run "git pair --global"
142
+ #result.should include "Unset --global user.name, user.email and user.initials"
143
+ expect_config result, "Aa Bb", "ab", "the-pair+aa@the-host.com"
144
+ result.should_not include("global:")
145
+ end
146
+ end
147
+
148
+ it "can set a single user as pair" do
149
+ result = run "git pair ab"
150
+ expect_config result, "Aa Bb", "ab", "the-pair+aa@the-host.com"
151
+ end
152
+
153
+ it "can set a 2 users as pair" do
154
+ result = run "git pair ab bc"
155
+ expect_config result, "Aa Bb and Bb Cc", "ab bc", "the-pair+aa+bb@the-host.com"
156
+ end
157
+
158
+ it "can set n users as pair" do
159
+ result = run "git pair ab bc cd"
160
+ expect_config result, "Aa Bb, Bb Cc and Cc Dd", "ab bc cd", "the-pair+aa+bb+cc@the-host.com"
161
+ end
162
+
163
+ it "prints names, email addresses, and initials in alphabetical order" do
164
+ result = run "git pair ab cd bc"
165
+ expect_config result, "Aa Bb, Bb Cc and Cc Dd", "ab bc cd", "the-pair+aa+bb+cc@the-host.com"
166
+ end
167
+
168
+ it "can set a user with apostrophes as pair" do
169
+ write ".pairs", File.read(".pairs").sub("Aa Bb", "Pete O'Connor")
170
+ result = run "git pair ab"
171
+ expect_config result, "Pete O'Connor", "ab", "the-pair+pete@the-host.com"
172
+ end
173
+
174
+ it "fails when there is no .git in the tree" do
175
+ run "rm -f /tmp/pairs"
176
+ run "cp .pairs /tmp"
177
+ Dir.chdir "/tmp" do
178
+ result = run "git pair ab 2>&1", :fail => true
179
+ result.should include("Not a git repository (or any of the parent directories)")
180
+ end
181
+ run "rm -f /tmp/pairs"
182
+ end
183
+
184
+ it "finds .pairs file in lower parent folder" do
185
+ run "mkdir foo"
186
+ Dir.chdir "foo" do
187
+ result = run "git pair ab"
188
+ expect_config result, "Aa Bb", "ab", "the-pair+aa@the-host.com"
189
+ end
190
+ end
191
+
192
+ it "unsets local config when no argument is passed" do
193
+ run "git pair ab --global"
194
+ run "git pair bc"
195
+ result = run "git pair"
196
+ result.should include "Unset user.name, user.email, user.initials"
197
+ expect_config result, "Aa Bb", "ab", "the-pair+aa@the-host.com", :global => true
198
+ result.should_not include("local:")
199
+ end
200
+
201
+ it "uses hard email when given" do
202
+ write ".pairs", File.read(".pairs").sub(/email:.*/m, "email: foo@bar.com")
203
+ result = run "git pair ab"
204
+ expect_config result, "Aa Bb", "ab", "foo@bar.com"
205
+ end
206
+
207
+ context "when no email config is present" do
208
+ before do
209
+ write ".pairs", File.read(".pairs").sub(/email:.*/m, "")
210
+ end
211
+
212
+ it "doesn't set email" do
213
+ run "git pair ab"
214
+ git_config_value('email').should be_empty
215
+ end
216
+
217
+ it "doesn't report about email" do
218
+ result = run "git pair ab"
219
+ result.should_not include "email"
220
+ end
221
+ end
222
+
223
+ it "uses no email prefix when only host is given" do
224
+ write ".pairs", File.read(".pairs").sub(/email:.*/m, "email:\n domain: foo.com")
225
+ result = run "git pair ab"
226
+ expect_config result, "Aa Bb", "ab", "aa@foo.com"
227
+ end
228
+
229
+ context "when no no_solo_prefix is given" do
230
+ before do
231
+ write ".pairs", File.read(".pairs").sub(/email:.*/m, "email:\n prefix: pairs\n no_solo_prefix: true\n domain: foo.com")
232
+ end
233
+
234
+ it "uses no email prefix for single developers" do
235
+ result = run "git pair ab"
236
+ expect_config result, "Aa Bb", "ab", "aa@foo.com"
237
+ end
238
+
239
+ it "uses email prefix for multiple developers" do
240
+ result = run "git pair ab bc"
241
+ expect_config result, "Aa Bb and Bb Cc", "ab bc", "pairs+aa+bb@foo.com"
242
+ end
243
+ end
244
+
245
+ it "fails with unknown initials" do
246
+ result = run "git pair xx", :fail => true
247
+ result.should include("Couldn't find author name for initials: xx")
248
+ end
249
+
250
+ it "uses alternate email prefix" do
251
+ write ".pairs", File.read(".pairs").sub(/ab:.*/, "ab: Aa Bb; blob")
252
+ result = run "git pair ab"
253
+ expect_config result, "Aa Bb", "ab", "the-pair+blob@the-host.com"
254
+ end
255
+ end
256
+
257
+ context "without a .pairs file in the tree" do
258
+ around do |example|
259
+ Dir.chdir "/tmp" do
260
+ run "rm -f .pairs"
261
+ dir = "git_stats_test"
262
+ run "rm -rf #{dir}"
263
+ run "mkdir #{dir}"
264
+ Dir.chdir dir do
265
+ run "git init"
266
+ example.run
267
+ end
268
+ run "rm -rf #{dir}"
269
+ end
270
+ end
271
+
272
+ context "and without a .pairs file in the home directory" do
273
+ it "fails if it cannot find a pairs file" do
274
+ run "git pair ab", :fail => true
275
+ end
276
+
277
+ it "prints instructions" do
278
+ result = run "git pair ab", :fail => true
279
+ result.should include("Could not find a .pairs file. Create a YAML file in your project or home directory.")
280
+ end
281
+ end
282
+
283
+ context "but a .pairs file in the home directory" do
284
+ around do |example|
285
+ file = File.join(ENV["HOME"], ".pairs")
286
+ write file, <<-YAML.unindent
287
+ pairs:
288
+ ab: Aa Bb
289
+ bc: Bb Cc
290
+ cd: Cc Dd
291
+
292
+ email:
293
+ prefix: the-pair
294
+ domain: the-host.com
295
+ YAML
296
+
297
+ example.run
298
+
299
+ FileUtils.rm file
300
+ end
301
+
302
+ it "loads the file" do
303
+ result = run "git pair ab"
304
+ expect_config result, "Aa Bb", "ab", "the-pair+aa@the-host.com"
305
+ end
306
+ end
307
+ end
308
+ end
309
+
310
+ describe 'pair-commit' do
311
+ before do
312
+ write ".pairs", <<-YAML.unindent
313
+ pairs:
314
+ ab: Aa Bb; abb
315
+ bc: Bb Cc; bcc
316
+ cd: Cc Dd; cdd
317
+
318
+ email:
319
+ prefix: the-pair
320
+ domain: the-host.com
321
+
322
+ email_addresses:
323
+ bc: test@other-host.com
324
+ YAML
325
+ end
326
+
327
+ context 'when a pair has been set' do
328
+ before do
329
+ run "git pair ab cd"
330
+ end
331
+
332
+ def author_name_of_last_commit
333
+ (run "git log -1 --pretty=%an").strip
334
+ end
335
+
336
+ def author_email_of_last_commit
337
+ (run "git log -1 --pretty=%ae").strip
338
+ end
339
+
340
+ def committer_name_of_last_commit
341
+ (run "git log -1 --pretty=%cn").strip
342
+ end
343
+
344
+ def committer_email_of_last_commit
345
+ (run "git log -1 --pretty=%ce").strip
346
+ end
347
+
348
+ def committer_email_and_key_of_last_commit
349
+ (run "git log -1 --pretty='%ae %GK'").strip
350
+ end
351
+
352
+ it "makes a commit" do
353
+ git_pair_commit
354
+ output = run "git log -1"
355
+ output.should include("Pair pare pear")
356
+ end
357
+
358
+ it "sets the author name to the pair's names" do
359
+ git_pair_commit
360
+ output = run "git log -1 --pretty=%an"
361
+ output.strip.should eq("Aa Bb and Cc Dd")
362
+ end
363
+
364
+ it "randomly chooses from pair and sets user.email" do
365
+ emails = 6.times.map do
366
+ git_pair_commit
367
+ author_email_of_last_commit
368
+ end.uniq
369
+ emails.should =~ ['abb@the-host.com', 'cdd@the-host.com']
370
+ end
371
+
372
+ context 'when git options are passed' do
373
+ it 'forwards those options to git' do
374
+ git_pair_commit
375
+ run 'git pair ab bc'
376
+ run 'git pair-commit --amend -C HEAD --reset-author'
377
+
378
+ output = run "git log -1 --pretty=%an"
379
+ output.strip.should eq("Aa Bb and Bb Cc")
380
+ end
381
+ end
382
+
383
+ context 'when the pair is set globally and the local repo has custom user name and email' do
384
+ before do
385
+ run 'git pair --global ab cd'
386
+ run "git config user.name 'Betty White'"
387
+ run "git config user.email 'betty@example.com'"
388
+ end
389
+
390
+ it 'still makes the commit with the correct user name' do
391
+ git_pair_commit
392
+
393
+ author_name_of_last_commit.should eq("Aa Bb and Cc Dd")
394
+ end
395
+
396
+ it 'still makes the commit with the correct user email' do
397
+ git_pair_commit
398
+
399
+ %w(abb@the-host.com cdd@the-host.com).should include(author_email_of_last_commit)
400
+ end
401
+
402
+ it 'still makes the commit with the correct committer name' do
403
+ git_pair_commit
404
+
405
+ committer_name_of_last_commit.should eq("Aa Bb and Cc Dd")
406
+ end
407
+
408
+ it 'still makes the commit with the correct committer email' do
409
+ git_pair_commit
410
+
411
+ %w(abb@the-host.com cdd@the-host.com).should include(committer_email_of_last_commit)
412
+ end
413
+ end
414
+
415
+ context 'when one of the pair has a custom email address' do
416
+ before do
417
+ run 'git pair ab bc'
418
+ end
419
+
420
+ it 'uses that email address' do
421
+ emails = 6.times.map do
422
+ git_pair_commit
423
+ author_email_of_last_commit
424
+ end.uniq
425
+ emails.should =~ ['abb@the-host.com', 'test@other-host.com']
426
+ end
427
+ end
428
+
429
+ context 'when gpg keys are configured' do
430
+ before do
431
+ run 'cat ../gpg-keys.asc | gpg --import >/dev/null 2>&1'
432
+ end
433
+
434
+ after do
435
+
436
+ end
437
+
438
+ context 'when one of the pair has a key' do
439
+ before do
440
+ File.open('.pairs', 'a') do |pairs|
441
+ pairs.puts <<-YAML.unindent
442
+ email_addresses:
443
+ ab: abb@other-host.com
444
+ bc: bcc@other-host.com
445
+ gpg_keys:
446
+ ab: 54E416F1
447
+ YAML
448
+ end
449
+
450
+ run 'git pair ab bc'
451
+ end
452
+
453
+ it 'uses that key with corresponding email' do
454
+ keys = 6.times.map do
455
+ git_pair_commit
456
+ committer_email_and_key_of_last_commit
457
+ end.uniq
458
+
459
+ keys =~ ['abb@other-host.com 54E416F1']
460
+ end
461
+
462
+ context 'when both pairs have a key' do
463
+ before do
464
+ File.open('.pairs', 'a') do |pairs|
465
+ pairs.puts <<-YAML.unindent
466
+ bc: 4A000CE7
467
+ YAML
468
+ end
469
+
470
+ run 'git pair ab bc'
471
+ end
472
+
473
+ it 'uses both keys corresponding emails' do
474
+ keys = 6.times.map do
475
+ git_pair_commit
476
+ committer_email_and_key_of_last_commit
477
+ end.uniq
478
+
479
+ keys =~ ['abb@other-host.com 54E416F1', 'bcc@other-host.com 4A000CE7']
480
+ end
481
+ end
482
+ end
483
+ end
484
+ end
485
+
486
+ context 'when no pair has been set' do
487
+ it 'raises an exception' do
488
+ git_pair_commit.should include('Error: No pair set')
489
+ end
490
+ end
491
+
492
+ context 'when -h flag is passed' do
493
+ it 'shows the help message' do
494
+ results = run 'git pair-commit -h'
495
+ results.gsub(/\s+/, ' ').should include('randomly chooses the author email from the members of the pair')
496
+ end
497
+ end
498
+
499
+ def git_pair_commit
500
+ run "echo #{rand(100)} > b"
501
+ run 'git add b'
502
+ run 'git pair-commit -m "Pair pare pear"', :fail => true
503
+ end
504
+ end
505
+ end