pivotal_git_scripts 1.1.4 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 753d8a062ae624181090e916384a9e8e701297dd
4
+ data.tar.gz: a650f7c1b75326dd6f220d6c3b0608e1e897a84f
5
+ SHA512:
6
+ metadata.gz: 305b19b837375798d916f98aec979e51d38a547cf44aa41333d3543402ac5e3a701f0362ac667fc6de1d50a4e6dc7e3687b6fc9246870edd30d06a4881814abd
7
+ data.tar.gz: eb1992aa9831cf19e157306129374a8b8bc5262584fb7f3d5c6a957ea39adc0c51a75884bcf31a661d19e9f17a12267ac5a836bb37e8c36fc7390f3dc73a66fa
data/.gitignore CHANGED
@@ -2,3 +2,4 @@ pkg/*
2
2
  *.gem
3
3
  .bundle
4
4
  spec/tmp
5
+ Gemfile.lock
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
4
+ - 2.0.0
5
+ - 1.9.3
6
+ - 1.9.2
7
+ # Fix weird issues from this Travis build:
8
+ # https://travis-ci.org/pivotal/git_scripts/jobs/5501358
9
+ # https://git.wiki.kernel.org/index.php/Git_FAQ#Git_commit_is_dying_telling_me_.22fatal:_empty_ident_.3Cuser.40myhost.3E_not_allowed.22.2C_what.27s_wrong.3F
10
+ env:
11
+ global:
12
+ - GIT_AUTHOR_NAME="Travis CI"
13
+ before_script:
14
+ - git config --global user.email "travis-ci@example.com"
15
+ - git config --global user.name "Travis CI"
@@ -0,0 +1,26 @@
1
+ # CHANGELOG
2
+
3
+ ## 1.4.0 - released 2015-01-15
4
+
5
+ ### `git pair-commit` explicitly sets the author name
6
+
7
+ Before this change, git's user.name setting would override. In
8
+ repositories where the user had previously run `git duet`, this meant
9
+ that after a `git pair --global ...` the email was set correctly by `git
10
+ pair-commit`, but the author name was not.
11
+
12
+ [#62606550]
13
+
14
+ ### `git pair-commit` sets committer name and email
15
+
16
+ [Finishes #62606550]
17
+
18
+ ### Add ability to use a custom email address per user
19
+
20
+ # include the following section to set custom email addresses for users
21
+ email_addresses:
22
+ zr: zach.robinson@example.com
23
+
24
+ ### Include the $HOME directory if it's not in the list of pwd ancestors.
25
+
26
+ This fixes the actual behavior to match the documentation, which states that the `.pairs` file may be in the user's home directory.
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in pivotal_git_scripts.gemspec
4
4
  gemspec
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Build Status](https://travis-ci.org/pivotal/git_scripts.png)](https://travis-ci.org/pivotal/git_scripts)
2
+
1
3
  # Git Scripts
2
4
 
3
5
  These scripts are helpers for managing developer workflow when using git repos hosted on GitHub. Install as a rubygem and they can be run as standard git commands like `git about`.
@@ -46,6 +48,27 @@ Options are:
46
48
  -v, --version Show Version
47
49
  -h, --help Show this.
48
50
 
51
+ ## git-pair-commit
52
+
53
+ Makes a git commit as normal, but chooses one of the pair members randomly to get credit for the commit on github (by setting the author email to that member's email address). The author name on the commit will list all members of the pair, as usual.
54
+
55
+ ### Using git-pair-commit in RubyMine
56
+ RubyMine already supports pointing at a custom location for your git executable in the Preferences -> Version Control -> Git
57
+ ![screen shot 2014-03-11 at 12 49 02 pm](https://f.cloud.github.com/assets/163532/2390097/49c3023e-a956-11e3-8aeb-dcba1a814309.png)
58
+ The trick then is that `pair-commit` doesn't encompass all git functionality, so you can't just point RubyMine directly at it, you need something in the middle that will use `pair-commit` if the first arg is `commit`, otherwise just pass through. Here's a ruby script to do just that:
59
+ ```ruby
60
+ #!/usr/bin/env ruby
61
+
62
+ exit_code = if ARGV[1] == "commit"
63
+ system "git pair-commit #{ARGV[1..-1].join(" ")}"
64
+ else
65
+ system "git #{ARGV.join(" ")}"
66
+ end
67
+
68
+ exit exit_code
69
+ ```
70
+ Make sure it's executable.
71
+
49
72
  ## git-project
50
73
 
51
74
  $ git project pivots
@@ -1,150 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- require 'yaml'
3
- require 'optparse'
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__)) # this is required when running from /usr/local/bin
3
+ require 'pivotal_git_scripts/git_pair'
4
4
 
5
- def parse_cli_options(argv)
6
- options = {}
7
- OptionParser.new do |opts|
8
- # copy-paste from readme
9
- opts.banner = <<BANNER.sub('<br/>','')
10
- Configures git authors when pair programming.
11
-
12
- git pair sp js
13
- user.name=Josh Susser & Sam Pierson
14
- user.email=pair+jsusser+sam@pivotallabs.com
15
-
16
-
17
- Create a `.pairs` config file in project root or your home folder.
18
-
19
- # .pairs - configuration for 'git pair'
20
- pairs:
21
- # <initials>: <Firstname> <Lastname>[; <email-id>]
22
- eh: Edward Hieatt
23
- js: Josh Susser; jsusser
24
- sf: Serguei Filimonov; serguei
25
- email:
26
- prefix: pair
27
- domain: pivotallabs.com
28
- # no_solo_prefix: true
29
- #global: true
30
-
31
-
32
- By default this affects the current project (.git/config).<br/>
33
- Use the `--global` option or add `global: true` to your `.pairs` file to set the global git configuration for all projects (~/.gitconfig).
34
-
35
- Options are:
36
- BANNER
37
- opts.on("-g", "--global", "Modify global git options instead of local") { options[:global] = true }
38
- opts.on("-v", "--version", "Show Version") do
39
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
40
- require "pivotal_git_scripts/version"
41
- puts PivotalGitScripts::VERSION
42
- exit
43
- end
44
- opts.on("-h", "--help", "Show this.") { puts opts; exit }
45
- end.parse!(argv)
46
-
47
- options
48
- end
49
-
50
- def read_pairs_config
51
- pairs_file_path = nil
52
- candidate_file_path = '.pairs'
53
- until pairs_file_path || File.expand_path(candidate_file_path) == '/.pairs' do
54
- if File.exists?(candidate_file_path)
55
- pairs_file_path = candidate_file_path
56
- else
57
- candidate_file_path = File.join("..", candidate_file_path)
58
- end
59
- end
60
-
61
- unless pairs_file_path
62
- puts <<-INSTRUCTIONS
63
- Could not find a .pairs file. Create a YAML file in your project or home directory.
64
- Format: <initials>: <name>[; <email>]
65
- Example:
66
- # .pairs - configuration for 'git pair'
67
- # place in project or home directory
68
- pairs:
69
- eh: Edward Hieatt
70
- js: Josh Susser; jsusser
71
- sf: Serguei Filimonov; serguei
72
- email:
73
- prefix: pair
74
- domain: pivotallabs.com
75
- INSTRUCTIONS
76
- exit(1)
77
- end
78
- pairs_file_path ? YAML.load_file(pairs_file_path) : {}
79
- end
80
-
81
- def read_author_info_from_config(config, initials)
82
- initials.map do |initials|
83
- if full_name = config['pairs'][initials.downcase]
84
- full_name
85
- else
86
- puts "Couldn't find author name for initials: #{initials}. Add this person to the .pairs file in your project or home directory."
87
- exit 1
88
- end
89
- end
90
- end
91
-
92
- def build_email(emails, config)
93
- if config.is_a?(Hash)
94
- prefix = config['prefix'] if !config['no_solo_prefix'] or emails.size > 1
95
- "#{([prefix] + emails).compact.join('+')}@#{config['domain']}"
96
- else
97
- config
98
- end
99
- end
100
-
101
- def set_git_config(global_config_string, options)
102
- options.each do |key,value|
103
- key = "user.#{key}"
104
- value = value ? %Q{#{key} "#{value}"} : "--unset #{key}"
105
- system(%Q{git config#{global_config_string} #{value}})
106
- end
107
- end
108
-
109
- def report_git_settings(git_dir, key)
110
- global = `git config --global --get-regexp '^user\.#{key}'`
111
- local = `git config -f #{git_dir}/config --get-regexp '^user\.#{key}'`
112
- if global.length > 0 && local.length > 0
113
- puts "NOTE: Overriding global user.#{key} setting with local."
114
- end
115
- puts "global: #{global}" if global.length > 0
116
- puts "local: #{local}" if local.length > 0
117
- end
118
-
119
- def extract_author_names_and_email_ids_from_config(config, initials)
120
- authors = read_author_info_from_config(config, initials)
121
- authors.sort!.uniq!
122
- authors.map do |a|
123
- full_name, email_id = a.split(";").map(&:strip)
124
- email_id ||= full_name.split(' ').first.downcase
125
- [full_name, email_id]
126
- end.transpose
127
- end
128
-
129
- git_dir = `git rev-parse --git-dir`.chomp
130
- exit 1 if git_dir.empty?
131
-
132
- options = parse_cli_options(ARGV)
133
- initials = ARGV
134
- config = read_pairs_config
135
- global = " --global" if options[:global] or config["global"]
136
-
137
- if initials.any?
138
- author_names, email_ids = extract_author_names_and_email_ids_from_config(config, initials)
139
- authors = [author_names[0..-2].join(", "), author_names.last].reject(&:empty?).join(" & ")
140
- email = build_email(email_ids, config["email"])
141
-
142
- set_git_config global, :name => authors, :email => email, :initials => initials.join(" ")
143
- else
144
- set_git_config global, :name => nil, :email => nil, :initials => nil
145
- puts "Unset#{global} user.name, user.email, user.initials"
146
- end
147
-
148
- [:name, :email, :initials].each do |key|
149
- report_git_settings(git_dir, key)
150
- end
5
+ PivotalGitScripts::GitPair.main(ARGV)
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__)) # this is required when running from /usr/local/bin
3
+ require 'pivotal_git_scripts/git_pair'
4
+
5
+ PivotalGitScripts::GitPair.commit(ARGV)
@@ -0,0 +1,251 @@
1
+ require "pivotal_git_scripts/version"
2
+ require 'yaml'
3
+ require 'optparse'
4
+ require 'pathname'
5
+
6
+ module PivotalGitScripts
7
+ module GitPair
8
+ def self.main(argv)
9
+ runner = Runner.new
10
+ runner.main(argv)
11
+ end
12
+
13
+ def self.commit(argv)
14
+ runner = Runner.new
15
+ runner.commit(argv)
16
+ end
17
+
18
+ class GitPairException < Exception; end
19
+
20
+ class Runner
21
+ def main(argv)
22
+ git_dir = `git rev-parse --git-dir`.chomp
23
+ exit 1 if git_dir.empty?
24
+
25
+ options = parse_cli_options(argv)
26
+ initials = argv
27
+ config = read_pairs_config
28
+ global = !!(options[:global] || config["global"])
29
+
30
+ if initials.any?
31
+ author_names, email_ids = extract_author_names_and_email_ids_from_config(config, initials)
32
+ authors = pair_names(author_names)
33
+ git_config = {:name => authors, :initials => initials.sort.join(" ")}
34
+ git_config[:email] = build_email(email_ids, config["email"]) unless no_email(config)
35
+ set_git_config global, git_config
36
+ else
37
+ git_config = {:name => nil, :initials => nil}
38
+ git_config[:email] = nil unless no_email(config)
39
+ set_git_config global, git_config
40
+ puts "Unset#{' global' if global} user.name, #{'user.email, ' unless no_email(config)}user.initials"
41
+ end
42
+
43
+ [:name, :email, :initials].each do |key|
44
+ report_git_settings(git_dir, key)
45
+ end
46
+ rescue GitPairException => e
47
+ puts e.message
48
+ exit 1
49
+ end
50
+
51
+ def commit(argv)
52
+ if argv[0] == '-h'
53
+ puts 'Usage: git pair-commit [options_for_git_commit]'
54
+ puts ''
55
+ puts 'Commits changes to the repository using `git commit`, but randomly chooses the author email from the'
56
+ puts 'members of the pair. In order for GitHub to assign credit for the commit activity, the user\'s email'
57
+ puts 'must be linked in their GitHub account.'
58
+ exit 0
59
+ end
60
+
61
+ config = read_pairs_config
62
+ author_details = extract_author_details_from_config(config, current_pair_initials)
63
+ author_names = author_details.keys.map { |i| author_details[i][:name] }
64
+ authors = pair_names(author_names)
65
+ author_email = random_author_email(author_details)
66
+ puts "Committing under #{author_email}"
67
+ passthrough_args = argv.map{|arg| "'#{arg}'"}.join(' ')
68
+ env_variables = "GIT_AUTHOR_NAME='#{authors}' GIT_AUTHOR_EMAIL='#{author_email}' GIT_COMMITTER_NAME='#{authors}' GIT_COMMITTER_EMAIL='#{author_email}'"
69
+ system "#{env_variables} git commit #{passthrough_args}"
70
+ rescue GitPairException => e
71
+ puts e.message
72
+ exit 1
73
+ end
74
+
75
+ def current_pair_initials
76
+ initials = `git config user.initials`.strip.split(' ')
77
+ raise GitPairException, 'Error: No pair set. Please set your pair with `git pair ...`' if initials.empty?
78
+ initials
79
+ end
80
+
81
+ def parse_cli_options(argv)
82
+ options = {}
83
+ OptionParser.new do |opts|
84
+ # copy-paste from readme
85
+ opts.banner = <<BANNER.sub('<br/>','')
86
+ Configures git authors when pair programming.
87
+
88
+ git pair sp js
89
+ user.name=Josh Susser and Sam Pierson
90
+ user.email=pair+jsusser+sam@pivotallabs.com
91
+
92
+
93
+ Create a `.pairs` config file in project root or your home folder.
94
+
95
+ # .pairs - configuration for 'git pair'
96
+ pairs:
97
+ # <initials>: <Firstname> <Lastname>[; <email-id>]
98
+ eh: Edward Hieatt
99
+ js: Josh Susser; jsusser
100
+ sf: Serguei Filimonov; serguei
101
+ # if email section is present, email will be set
102
+ # if you leave out the email config section, email will not be set
103
+ email:
104
+ prefix: pair
105
+ domain: pivotallabs.com
106
+ # no_solo_prefix: true
107
+ #global: true
108
+ # include the following section to set custom email addresses for users
109
+ #email_addresses:
110
+ # zr: zach.robinson@example.com
111
+
112
+
113
+ By default this affects the current project (.git/config).<br/>
114
+ Use the `--global` option or add `global: true` to your `.pairs` file to set the global git configuration for all projects (~/.gitconfig).
115
+
116
+ Options are:
117
+ BANNER
118
+ opts.on("-g", "--global", "Modify global git options instead of local") { options[:global] = true }
119
+ opts.on("-v", "--version", "Show Version") do
120
+ puts PivotalGitScripts::VERSION
121
+ exit
122
+ end
123
+ opts.on("-h", "--help", "Show this.") { puts opts; exit }
124
+ end.parse!(argv)
125
+
126
+ options
127
+ end
128
+
129
+ def read_pairs_config
130
+ pairs_file_name = '.pairs'
131
+
132
+ directory = File.absolute_path(Dir.pwd)
133
+ candidate_directories = [directory]
134
+ while ! Pathname.new(directory).root? do
135
+ directory = File.absolute_path(File.join(directory, ".."))
136
+ candidate_directories << directory
137
+ end
138
+ home = File.absolute_path(ENV["HOME"])
139
+ candidate_directories << home unless candidate_directories.include? home
140
+
141
+ pairs_file_path = candidate_directories.
142
+ map { |d| File.join(d, ".pairs") }.
143
+ find { |f| File.exists? f }
144
+
145
+ unless pairs_file_path
146
+ raise GitPairException, <<-INSTRUCTIONS
147
+ Could not find a .pairs file. Create a YAML file in your project or home directory.
148
+ Format: <initials>: <name>[; <email>]
149
+ Example:
150
+ # .pairs - configuration for 'git pair'
151
+ # place in project or home directory
152
+ pairs:
153
+ eh: Edward Hieatt
154
+ js: Josh Susser; jsusser
155
+ sf: Serguei Filimonov; serguei
156
+ email:
157
+ prefix: pair
158
+ domain: pivotallabs.com
159
+ INSTRUCTIONS
160
+ end
161
+
162
+ YAML.load_file(pairs_file_path)
163
+ end
164
+
165
+ def read_author_info_from_config(config, initials_ary)
166
+ initials_ary.map do |initials|
167
+ config['pairs'][initials.downcase] or
168
+ raise GitPairException, "Couldn't find author name for initials: #{initials}. Add this person to the .pairs file in your project or home directory."
169
+ end
170
+ end
171
+
172
+ def build_email(emails, config)
173
+ if config.is_a?(Hash)
174
+ prefix = config['prefix'] if !config['no_solo_prefix'] or emails.size > 1
175
+ "#{([prefix] + emails).compact.join('+')}@#{config['domain']}"
176
+ else
177
+ config
178
+ end
179
+ end
180
+
181
+ def random_author_email(author_details)
182
+ author_id = author_details.keys.sample
183
+ author_details[author_id][:email]
184
+ end
185
+
186
+ def set_git_config(global, options)
187
+ options.each do |key,value|
188
+ config_key = "user.#{key}"
189
+ arg = value ? %Q{#{config_key} "#{value}"} : "--unset #{config_key}"
190
+ system(%Q{git config#{' --global' if global} #{arg}})
191
+ end
192
+ end
193
+
194
+ def report_git_settings(git_dir, key)
195
+ global = `git config --global --get-regexp '^user\.#{key}'`
196
+ local = `git config -f #{git_dir}/config --get-regexp '^user\.#{key}'`
197
+ if global.length > 0 && local.length > 0
198
+ puts "NOTE: Overriding global user.#{key} setting with local."
199
+ end
200
+ puts "global: #{global}" if global.length > 0
201
+ puts "local: #{local}" if local.length > 0
202
+ end
203
+
204
+ def extract_author_names_and_email_ids_from_config(config, initials)
205
+ authors = read_author_info_from_config(config, initials)
206
+ authors.sort!.uniq! # FIXME
207
+ authors.map do |a|
208
+ full_name, email_id = a.split(";").map(&:strip)
209
+ email_id ||= full_name.split(' ').first.downcase
210
+ [full_name, email_id]
211
+ end.transpose
212
+ end
213
+
214
+ def no_email(config)
215
+ !config.key? 'email'
216
+ end
217
+
218
+ def extract_author_details_from_config(config, initials)
219
+ details = {}
220
+
221
+ initials.each do |i|
222
+ info = read_author_info_from_config(config, [i]).first
223
+
224
+ full_name, email_id = info.split(";").map(&:strip)
225
+ email_id ||= full_name.split(' ').first.downcase
226
+
227
+ email = read_custom_email_address_from_config(config, i)
228
+ email ||= "#{email_id}@#{config['email']['domain']}"
229
+
230
+ details[i] = {
231
+ :name => full_name,
232
+ :email => email
233
+ }
234
+ end
235
+
236
+ details
237
+ end
238
+
239
+ def read_custom_email_address_from_config(config, initial)
240
+ return nil unless config['email_addresses']
241
+ return config['email_addresses'][initial.downcase]
242
+ end
243
+
244
+ private
245
+
246
+ def pair_names(author_names)
247
+ [author_names[0..-2].join(", "), author_names.last].reject(&:empty?).join(" and ")
248
+ end
249
+ end
250
+ end
251
+ end
@@ -1,3 +1,3 @@
1
1
  module PivotalGitScripts
2
- VERSION = "1.1.4"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -7,9 +7,13 @@ describe "CLI" do
7
7
  end
8
8
 
9
9
  def run(command, options={})
10
- result = `#{command}`
11
- raise "FAILED #{command} : #{result}" if $?.success? == !!options[:fail]
12
- result
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
13
17
  end
14
18
 
15
19
  def write(file, content)
@@ -23,10 +27,17 @@ describe "CLI" do
23
27
 
24
28
  # use fake home for .ssh hacks
25
29
  run "mkdir #{dir}/home"
26
- ENV["HOME"] = File.expand_path("#{dir}/home")
30
+ ENV["HOME"] = File.absolute_path("#{dir}/home")
27
31
 
28
32
  Dir.chdir dir do
29
- run "touch a && git init && git add . && git commit -am 'initial'"
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"
30
41
  example.run
31
42
  end
32
43
  end
@@ -82,6 +93,11 @@ describe "CLI" do
82
93
  result.should include "#{prefix}user.email #{email}"
83
94
  end
84
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
+
85
101
  it "prints help" do
86
102
  result = run "git-pair --help"
87
103
  result.should include("Configures git authors when pair programming")
@@ -136,12 +152,17 @@ describe "CLI" do
136
152
 
137
153
  it "can set a 2 users as pair" do
138
154
  result = run "git pair ab bc"
139
- expect_config result, "Aa Bb & Bb Cc", "ab bc", "the-pair+aa+bb@the-host.com"
155
+ expect_config result, "Aa Bb and Bb Cc", "ab bc", "the-pair+aa+bb@the-host.com"
140
156
  end
141
157
 
142
158
  it "can set n users as pair" do
143
159
  result = run "git pair ab bc cd"
144
- expect_config result, "Aa Bb, Bb Cc & Cc Dd", "ab bc cd", "the-pair+aa+bb+cc@the-host.com"
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"
145
166
  end
146
167
 
147
168
  it "can set a user with apostrophes as pair" do
@@ -183,6 +204,22 @@ describe "CLI" do
183
204
  expect_config result, "Aa Bb", "ab", "foo@bar.com"
184
205
  end
185
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
+
186
223
  it "uses no email prefix when only host is given" do
187
224
  write ".pairs", File.read(".pairs").sub(/email:.*/m, "email:\n domain: foo.com")
188
225
  result = run "git pair ab"
@@ -201,7 +238,7 @@ describe "CLI" do
201
238
 
202
239
  it "uses email prefix for multiple developers" do
203
240
  result = run "git pair ab bc"
204
- expect_config result, "Aa Bb & Bb Cc", "ab bc", "pairs+aa+bb@foo.com"
241
+ expect_config result, "Aa Bb and Bb Cc", "ab bc", "pairs+aa+bb@foo.com"
205
242
  end
206
243
  end
207
244
 
@@ -232,14 +269,177 @@ describe "CLI" do
232
269
  end
233
270
  end
234
271
 
235
- it "fails if it cannot find a pairs file" do
236
- run "git pair ab", :fail => true
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
237
334
  end
238
335
 
239
- it "prints instructions" do
240
- result = run "git pair ab", :fail => true
241
- result.should include("Could not find a .pairs file. Create a YAML file in your project or home directory.")
336
+ def author_email_of_last_commit
337
+ (run "git log -1 --pretty=%ae").strip
242
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
+ it "makes a commit" do
349
+ git_pair_commit
350
+ output = run "git log -1"
351
+ output.should include("Pair pare pear")
352
+ end
353
+
354
+ it "sets the author name to the pair's names" do
355
+ git_pair_commit
356
+ output = run "git log -1 --pretty=%an"
357
+ output.strip.should eq("Aa Bb and Cc Dd")
358
+ end
359
+
360
+ it "randomly chooses from pair and sets user.email" do
361
+ emails = 6.times.map do
362
+ git_pair_commit
363
+ author_email_of_last_commit
364
+ end.uniq
365
+ emails.should =~ ['abb@the-host.com', 'cdd@the-host.com']
366
+ end
367
+
368
+ context 'when git options are passed' do
369
+ it 'forwards those options to git' do
370
+ git_pair_commit
371
+ run 'git pair ab bc'
372
+ run 'git pair-commit --amend -C HEAD --reset-author'
373
+
374
+ output = run "git log -1 --pretty=%an"
375
+ output.strip.should eq("Aa Bb and Bb Cc")
376
+ end
377
+ end
378
+
379
+ context 'when the pair is set globally and the local repo has custom user name and email' do
380
+ before do
381
+ run 'git pair --global ab cd'
382
+ run "git config user.name 'Betty White'"
383
+ run "git config user.email 'betty@example.com'"
384
+ end
385
+
386
+ it 'still makes the commit with the correct user name' do
387
+ git_pair_commit
388
+
389
+ author_name_of_last_commit.should eq("Aa Bb and Cc Dd")
390
+ end
391
+
392
+ it 'still makes the commit with the correct user email' do
393
+ git_pair_commit
394
+
395
+ %w(abb@the-host.com cdd@the-host.com).should include(author_email_of_last_commit)
396
+ end
397
+
398
+ it 'still makes the commit with the correct committer name' do
399
+ git_pair_commit
400
+
401
+ committer_name_of_last_commit.should eq("Aa Bb and Cc Dd")
402
+ end
403
+
404
+ it 'still makes the commit with the correct committer email' do
405
+ git_pair_commit
406
+
407
+ %w(abb@the-host.com cdd@the-host.com).should include(committer_email_of_last_commit)
408
+ end
409
+ end
410
+
411
+ context 'when one of the pair has a custom email address' do
412
+ before do
413
+ run 'git pair ab bc'
414
+ end
415
+
416
+ it 'uses that email address' do
417
+ emails = 6.times.map do
418
+ git_pair_commit
419
+ author_email_of_last_commit
420
+ end.uniq
421
+ emails.should =~ ['abb@the-host.com', 'test@other-host.com']
422
+ end
423
+ end
424
+ end
425
+
426
+ context 'when no pair has been set' do
427
+ it 'raises an exception' do
428
+ git_pair_commit.should include('Error: No pair set')
429
+ end
430
+ end
431
+
432
+ context 'when -h flag is passed' do
433
+ it 'shows the help message' do
434
+ results = run 'git pair-commit -h'
435
+ results.gsub(/\s+/, ' ').should include('randomly chooses the author email from the members of the pair')
436
+ end
437
+ end
438
+
439
+ def git_pair_commit
440
+ run "echo #{rand(100)} > b"
441
+ run 'git add b'
442
+ run 'git pair-commit -m "Pair pare pear"', :fail => true
243
443
  end
244
444
  end
245
445
  end
@@ -0,0 +1,52 @@
1
+ require 'pivotal_git_scripts/git_pair'
2
+
3
+ describe PivotalGitScripts::GitPair::Runner do
4
+ let(:runner) { described_class.new }
5
+
6
+ describe 'set_git_config' do
7
+ it 'calls git config with pairs in the options' do
8
+ runner.should_receive(:system).with('git config user.foo "bar baz"')
9
+
10
+ runner.set_git_config(false, 'foo' => 'bar baz')
11
+ end
12
+
13
+ it 'can unset git config options' do
14
+ runner.should_receive(:system).with('git config --unset user.foo')
15
+
16
+ runner.set_git_config(false, 'foo' => nil)
17
+ end
18
+
19
+ it 'can handle multiple pairs in a hash' do
20
+ runner.should_receive(:system).with('git config --unset user.remove')
21
+ runner.should_receive(:system).with('git config user.ten "10"')
22
+
23
+ runner.set_git_config(false, 'remove' => nil, 'ten' => '10')
24
+ end
25
+
26
+ it 'supports a global option' do
27
+ runner.should_receive(:system).with('git config --global user.foo "bar baz"')
28
+
29
+ runner.set_git_config(true, 'foo' => 'bar baz')
30
+ end
31
+ end
32
+
33
+ describe 'read_author_info_from_config' do
34
+ it 'maps from the initials to the full name' do
35
+ config = {
36
+ 'pairs' => {
37
+ 'aa' => 'An Aardvark',
38
+ 'tt' => 'The Turtle'
39
+ }
40
+ }
41
+
42
+ names = runner.read_author_info_from_config(config, ['aa', 'tt'])
43
+ names.should =~ ['An Aardvark', 'The Turtle']
44
+ end
45
+
46
+ it 'exits when initials cannot be found' do
47
+ expect {
48
+ runner.read_author_info_from_config({"pairs" => {}}, ['aa'])
49
+ }.to raise_error(PivotalGitScripts::GitPair::GitPairException)
50
+ end
51
+ end
52
+ end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pivotal_git_scripts
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
5
- prerelease:
4
+ version: 1.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Pivotal Labs
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-03-15 00:00:00.000000000Z
11
+ date: 2015-01-15 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: These scripts are helpers for managing developer workflow when using
15
14
  git repos hosted on GitHub.
@@ -18,49 +17,53 @@ email:
18
17
  executables:
19
18
  - git-about
20
19
  - git-pair
20
+ - git-pair-commit
21
21
  - git-project
22
22
  - git-superpull
23
23
  extensions: []
24
24
  extra_rdoc_files: []
25
25
  files:
26
- - .gitignore
27
- - .rspec
26
+ - ".gitignore"
27
+ - ".rspec"
28
+ - ".travis.yml"
29
+ - CHANGELOG.md
28
30
  - Gemfile
29
- - Gemfile.lock
30
31
  - MIT.LICENSE
31
32
  - README.md
32
33
  - Rakefile
33
34
  - bin/git-about
34
35
  - bin/git-pair
36
+ - bin/git-pair-commit
35
37
  - bin/git-project
36
38
  - bin/git-superpull
39
+ - lib/pivotal_git_scripts/git_pair.rb
37
40
  - lib/pivotal_git_scripts/version.rb
38
41
  - pivotal_git_scripts.gemspec
39
42
  - spec/cli_spec.rb
43
+ - spec/git_pair_spec.rb
40
44
  homepage: http://github.com/pivotal/git_scripts
41
45
  licenses:
42
46
  - MIT
47
+ metadata: {}
43
48
  post_install_message:
44
49
  rdoc_options: []
45
50
  require_paths:
46
51
  - lib
47
52
  required_ruby_version: !ruby/object:Gem::Requirement
48
- none: false
49
53
  requirements:
50
- - - ! '>='
54
+ - - ">="
51
55
  - !ruby/object:Gem::Version
52
56
  version: '0'
53
57
  required_rubygems_version: !ruby/object:Gem::Requirement
54
- none: false
55
58
  requirements:
56
- - - ! '>='
59
+ - - ">="
57
60
  - !ruby/object:Gem::Version
58
61
  version: '0'
59
62
  requirements: []
60
63
  rubyforge_project: pivotal_git_scripts
61
- rubygems_version: 1.8.6
64
+ rubygems_version: 2.2.2
62
65
  signing_key:
63
- specification_version: 3
66
+ specification_version: 4
64
67
  summary: Developer git workflow convenience scripts
65
- test_files:
66
- - spec/cli_spec.rb
68
+ test_files: []
69
+ has_rdoc:
@@ -1,29 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- pivotal_git_scripts (1.1.4)
5
-
6
- GEM
7
- remote: http://rubygems.org/
8
- specs:
9
- diff-lcs (1.1.3)
10
- rake (0.9.2.2)
11
- rspec (2.8.0)
12
- rspec-core (~> 2.8.0)
13
- rspec-expectations (~> 2.8.0)
14
- rspec-mocks (~> 2.8.0)
15
- rspec-core (2.8.0)
16
- rspec-expectations (2.8.0)
17
- diff-lcs (~> 1.1.2)
18
- rspec-mocks (2.8.0)
19
- unindent (1.0)
20
-
21
- PLATFORMS
22
- ruby
23
-
24
- DEPENDENCIES
25
- bundler
26
- pivotal_git_scripts!
27
- rake
28
- rspec
29
- unindent