mavenlink-git-scripts 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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