edsinclair-git-pair 0.3.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.
data/.autotest ADDED
@@ -0,0 +1,5 @@
1
+ Autotest.add_hook :initialize do |autotest|
2
+ [/\.git/, /pkg\//, /\.gemspec$/, /\.log$/].each do |regexp|
3
+ autotest.add_exception regexp
4
+ end
5
+ end
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ *.gem
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in git-pair.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Chris Kampmeier
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # git-pair
2
+
3
+ A git porcelain for changing `user.name` and `user.email` so you can commit as
4
+ more than one author.
5
+
6
+ ## Usage
7
+
8
+ Install the gem:
9
+
10
+ gem install edsinclair-git-pair
11
+
12
+ And here's how to use it!
13
+
14
+ $ git pair
15
+
16
+ General Syntax:
17
+ git pair [reset | authors | options]
18
+
19
+ Options:
20
+ -a, --add AUTHOR Add an author. Format: "Author Name <author@example.com>"
21
+ -r, --remove NAME Remove an author. Use the full name.
22
+ -d, --reset Reset current author to default (global) config
23
+ -s, --show 'aa [bb]' Show the string to be used for the commit author field
24
+ --install-hook Install a post-commit hook for the current repo. See git-pair/hooks/post-commit for more information.
25
+ --email EMAIL Add a default email address to be used for pairs
26
+
27
+ Switching authors:
28
+ git pair aa [bb] Where AA and BB are any abbreviation of an
29
+ author's name. You can specify one or more authors.
30
+
31
+ Current config:
32
+ Author list: Adam McCrea
33
+ Jon Distad
34
+
35
+ Current author: Jon Distad + Adam McCrea
36
+ Current email: devs+jd+am@edgecase.com
37
+
38
+ ## How does it work?
39
+
40
+ The list of authors is maintained in the global git configuration file.
41
+ The current author is set in the git configuration local to the project.
42
+ The email address for a pair will be generated using the first author's email
43
+ domain and the initials separated by a '+' will precede the '@'.
44
+ Alternatively you can specify an email address to be used for pair commits.
45
+ For example: if you specify pair@example.net the pair email address will be pair+aa+bb@example.net
46
+
47
+ ## About this version
48
+
49
+ This was forked from http://github.com/edgecase/git-pair which in turn was
50
+ forked from http://github.com/chrisk/git-pair. Many thanks to Chris Kampmeier
51
+ for the original version and Adam McCrea, John Distad and Ehren Murdick for the
52
+ features they added to the edgecase release. This version adds a --show, --email
53
+ and --install-hook options and converts the gem to use Bundler for dependency management.
54
+
55
+ ## License
56
+
57
+ Copyright (c) 2009 Chris Kampmeier. See `LICENSE` for details.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+ Bundler.setup
4
+ require 'bundler/gem_tasks'
5
+
6
+ begin
7
+ require 'cucumber/rake/task'
8
+ Cucumber::Rake::Task.new(:features)
9
+ task :features
10
+ rescue LoadError
11
+ task :features do
12
+ abort "Cucumber is not available. In order to run features, you must: sudo gem install cucumber"
13
+ end
14
+ end
15
+
16
+ task :default => :features
17
+
18
+ # Don't print commands when shelling out (for example, running Cucumber)
19
+ RakeFileUtils.verbose(false)
data/bin/git-pair ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'git-pair'
4
+ require 'git-pair/command'
5
+
6
+ GitPair::Command.run!(ARGV)
@@ -0,0 +1,3 @@
1
+ default: --format progress --color features
2
+ autotest: --format pretty
3
+ autotest-all: --profile default
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "git-pair/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "edsinclair-git-pair"
7
+ s.version = GitPair::VERSION
8
+ s.authors = ["Chris Kampmeier", "Adam McCrea", "Jon Distad", "Eirik Dentz Sinclair", "Tim Gildea"]
9
+ s.email = ["eirik@efficiency20.com"]
10
+ s.homepage = ""
11
+ s.date = %q{2011-08-24}
12
+ s.summary = %q{Configure git to commit as more than one author}
13
+ s.description = %q{A git porcelain for pair programming. Changes git-config's user.name and user.email settings so you can commit as more than one author.}
14
+
15
+ s.rubyforge_project = "git-pair"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ s.add_development_dependency "cucumber"
22
+ s.add_development_dependency "ruby-debug"
23
+ end
@@ -0,0 +1,27 @@
1
+ Feature: Adding an author
2
+ In order to commit as a pair
3
+ A user should be able to
4
+ add a name and email to the list of authors
5
+
6
+ Scenario: adding a name and email
7
+ When I add the author "Linus Torvalds <linus@example.org>"
8
+ Then `git pair` should display "Linus Torvalds" in its author list
9
+
10
+ Scenario: adding the same name and email twice
11
+ When I add the author "Linus Torvalds <linus@example.org>"
12
+ And I add the author "Linus Torvalds <linus@example.org>"
13
+ Then `git pair` should display "Linus Torvalds" in its author list only once
14
+ And the gitconfig should include "Linus Torvalds" in its author list only once
15
+
16
+ Scenario: adding the same name twice with different emails
17
+ When I add the author "Linus Torvalds <linus@example.org>"
18
+ And I add the author "Linus Torvalds <linus@example.com>"
19
+ Then `git pair` should display "Linus Torvalds" in its author list only once
20
+ And the gitconfig should include "Linus Torvalds" in its author list only once
21
+ And the gitconfig should include "linus@example.org" as the email of "Linus Torvalds"
22
+
23
+ Scenario: adding a malformed author string
24
+ When I add the author " "
25
+ And I add the author "Bob Dole"
26
+ And I add the author "Jimmy <asdf"
27
+ Then the config file should have no authors
@@ -0,0 +1,33 @@
1
+ Feature: seeing authors on console
2
+ In order to see the current author
3
+ A user should be able to
4
+ get the author string for a set of initials
5
+
6
+ Scenario: No authors have been added
7
+ When I specify the initials "AA BB"
8
+ Then the last command's output should include "Please add some authors first"
9
+
10
+ Scenario: A single author
11
+ Given I have added the author "Linus Torvalds <linus@example.net>"
12
+ When I specify the initials "LT"
13
+ Then the last command's output should include "Linus Torvalds <linus@example.net>"
14
+
15
+ Scenario: Two authors
16
+ Given I have added the author "Linus Torvalds <linus@example.net>"
17
+ And I have added the author "Junio C Hamano <junio@example.org>"
18
+ And my global Git configuration is setup with email "devs@example.com"
19
+ When I specify the initials "LT JCH"
20
+ Then the last command's output should include "Linus Torvalds & Junio C Hamano <lt+jch@example.net>"
21
+
22
+ Scenario: A single author and the pair email has been set
23
+ Given I have set the pair email to "devs@widgets.com"
24
+ And I have added the author "Linus Torvalds <linus@example.net>"
25
+ When I specify the initials "LT"
26
+ Then the last command's output should include "Linus Torvalds <linus@example.net>"
27
+
28
+ Scenario: Pairing with two authors and the pair email has been set
29
+ Given I have set the pair email to "devs@widgets.com"
30
+ And I have added the author "Linus Torvalds <linus@example.net>"
31
+ And I have added the author "Junio C Hamano <junio@example.org>"
32
+ When I specify the initials "LT JCH"
33
+ Then the last command's output should include "Linus Torvalds & Junio C Hamano <devs+lt+jch@widgets.com>"
@@ -0,0 +1,19 @@
1
+ Feature: Adding an author
2
+ In order remove old pairing partners
3
+ A user should be able to
4
+ remove a name from the list of authors
5
+
6
+ Scenario: removing a name
7
+ When I add the author "Linus Torvalds <linus@example.org>"
8
+ And I add the author "Junio C Hamano <junio@example.org>"
9
+ And I remove the name "Junio C Hamano"
10
+ Then `git pair` should display the following author list:
11
+ | name |
12
+ | Linus Torvalds |
13
+
14
+ Scenario: removing all names
15
+ When I add the author "Linus Torvalds <linus@example.org>"
16
+ And I add the author "Junio C Hamano <junio@example.org>"
17
+ And I remove the name "Linus Torvalds"
18
+ And I remove the name "Junio C Hamano"
19
+ Then `git pair` should display an empty author list
@@ -0,0 +1,11 @@
1
+ Feature: Resetting the pair
2
+ In order reset to the global author
3
+ A user should be able to
4
+ reset to the Global User
5
+
6
+ Scenario: resetting the current authors
7
+ Given I have added the author "Linus Torvalds <linus@example.org>"
8
+ And my global Git configuration is setup with user "Global User"
9
+ And I switch to the pair "LT"
10
+ When I reset the current authors
11
+ Then `git pair` should display "Global User" for the current author
@@ -0,0 +1,8 @@
1
+ Feature: Setting a pair email
2
+ In order to commit as a pair
3
+ A user should be able to
4
+ set a pair email address
5
+
6
+ Scenario: setting a pair email
7
+ When I set the pair email to "pair@widgets.com"
8
+ Then `git pair` should display "pair@widgets.com" as its pair email
@@ -0,0 +1,120 @@
1
+ Given /^I have added the author "([^\"]*)"$/ do |name_and_email|
2
+ When %(I add the author "#{name_and_email}")
3
+ end
4
+
5
+ Given /^my global Git configuration is setup with user "([^\"]*)"$/ do |name|
6
+ git_config "--global user.name \"#{name}\""
7
+ end
8
+
9
+ Given /^my global Git configuration is setup with email "([^\"]*)"$/ do |email|
10
+ git_config "--global user.email \"#{email}\""
11
+ end
12
+
13
+ When /^I (?:have )?set the pair email to "([^"]*)"$/ do |email|
14
+ git_pair %(--email "#{email}")
15
+ end
16
+
17
+ Then /^`git pair` should display "([^"]*)" as its pair email$/ do |email|
18
+ output = git_pair
19
+ assert_equal email, current_pair_email_from_output(output)
20
+ end
21
+
22
+ When /^I add the author "([^\"]*)"$/ do |name_and_email|
23
+ git_pair %(--add "#{name_and_email}")
24
+ end
25
+
26
+ When /^I remove the name "([^\"]*)"$/ do |name|
27
+ git_pair %(--remove "#{name}")
28
+ end
29
+
30
+ When /^I specify the initials "([^"]*)"$/ do |abbreviations|
31
+ @output = git_pair %(--show "#{abbreviations}")
32
+ end
33
+
34
+ When /^I (?:try to )?switch to the pair "([^\"]*)"$/ do |abbreviations|
35
+ @output = git_pair abbreviations
36
+ end
37
+
38
+ When /^I reset the current authors$/ do
39
+ git_pair '--reset'
40
+ end
41
+
42
+ Then /^`git pair` should display "([^\"]*)" in its author list$/ do |name|
43
+ output = git_pair
44
+ authors = authors_list_from_output(output)
45
+ assert authors.include?(name)
46
+ end
47
+
48
+ Then /^`git pair` should display "([^\"]*)" in its author list only once$/ do |name|
49
+ output = git_pair
50
+ authors = authors_list_from_output(output)
51
+ assert_equal 1, authors.select { |author| author == name}.size
52
+ end
53
+
54
+ Then /^`git pair` should display no authors$/ do
55
+ output = git_pair
56
+ authors = authors_list_from_output(output)
57
+ authors.size.should be_zero
58
+ end
59
+
60
+
61
+ Then /^`git pair` should display "([^\"]*)" for the current author$/ do |names|
62
+ output = git_pair
63
+ assert_equal names, current_author_from_output(output)
64
+ end
65
+
66
+ Then /^`git pair` should display "([^\"]*)" for the current email$/ do |email|
67
+ output = git_pair
68
+ assert_equal email, current_email_from_output(output)
69
+ end
70
+
71
+ Then /^the gitconfig should include "([^\"]*)" in its author list only once$/ do |name|
72
+ output = git_config
73
+ authors = output.split("\n").map { |line| line =~ /^git-pair\.authors=(.*) <[^>]+>$/; $1 }.compact
74
+ assert_equal 1, authors.select { |author| author == name}.size
75
+ end
76
+
77
+ Then /^the gitconfig should include "([^\"]*)" as the email of "([^\"]*)"$/ do |email, name|
78
+ output = git_config
79
+ authors = output.split("\n").map { |line| line =~ /^git-pair\.authors=.* <([^>]+)>$/; $1 }.compact
80
+ assert_equal 1, authors.select { |author| author == email}.size
81
+ end
82
+
83
+ Then /^`git pair` should display the following author list:$/ do |table|
84
+ output = git_pair
85
+ names = authors_list_from_output(output).map { |name| {"name" => name} }
86
+ table.diff! names
87
+ end
88
+
89
+ Then /^`git pair` should display an empty author list$/ do
90
+ output = git_pair
91
+ assert authors_list_from_output(output).empty?
92
+ end
93
+
94
+ Then /^the last command's output should include "([^\"]*)"$/ do |output|
95
+ assert @output.include?(output)
96
+ end
97
+
98
+ Then /^the config file should have no authors$/ do
99
+ assert git_config(%(--global --get-all git-pair.authors)).empty?
100
+ end
101
+
102
+ def current_pair_email_from_output(output)
103
+ output =~ /Pair email: (.*?)\n/im
104
+ $1.strip
105
+ end
106
+
107
+ def authors_list_from_output(output)
108
+ output =~ /Author list: (.*?)\n\s?\n/im
109
+ $1.strip.split("\n").map { |name| name.strip }
110
+ end
111
+
112
+ def current_author_from_output(output)
113
+ output =~ /Current author: (.*?)\n/im
114
+ $1.strip
115
+ end
116
+
117
+ def current_email_from_output(output)
118
+ output =~ /Current email: (.*?)\n/im
119
+ $1.strip
120
+ end
@@ -0,0 +1,50 @@
1
+ require 'tmpdir'
2
+ require 'test/unit/assertions'
3
+ World(Test::Unit::Assertions)
4
+
5
+
6
+ module RepositoryHelper
7
+ # TODO: use 1.8.7's Dir.mktmpdir?
8
+ TEST_REPO_PATH = File.join(Dir::tmpdir, "git-pair-test-repo")
9
+ TEST_REPO_DOT_GIT_PATH = "#{TEST_REPO_PATH}/.git"
10
+
11
+ PROJECT_PATH = File.join(File.dirname(__FILE__), "../..")
12
+ GIT_PAIR = "#{PROJECT_PATH}/bin/git-pair"
13
+ CONFIG_BACKUP_PATH = "#{PROJECT_PATH}/tmp"
14
+
15
+ def git_pair(options = "")
16
+ output = `HOME=#{TEST_REPO_PATH} GIT_DIR=#{TEST_REPO_DOT_GIT_PATH} #{GIT_PAIR} #{options} 2>&1`
17
+ output.gsub(/\e\[\d\d?m/, '') # strip any ANSI colors
18
+ end
19
+
20
+ def git_config(options = nil)
21
+ options ||= "--list"
22
+ `HOME=#{TEST_REPO_PATH} GIT_DIR=#{TEST_REPO_DOT_GIT_PATH} git config #{options} 2>&1`
23
+ end
24
+
25
+ def backup_gitconfigs
26
+ FileUtils.mkdir_p CONFIG_BACKUP_PATH
27
+ FileUtils.cp File.expand_path("~/.gitconfig"), "#{CONFIG_BACKUP_PATH}/.gitconfig.backup"
28
+ FileUtils.cp "#{PROJECT_PATH}/.git/config", "#{CONFIG_BACKUP_PATH}/config.backup"
29
+ end
30
+
31
+ def restore_gitconfigs
32
+ FileUtils.cp "#{CONFIG_BACKUP_PATH}/config.backup", "#{PROJECT_PATH}/.git/config"
33
+ FileUtils.cp "#{CONFIG_BACKUP_PATH}/.gitconfig.backup", File.expand_path("~/.gitconfig")
34
+ FileUtils.rm_rf CONFIG_BACKUP_PATH
35
+ end
36
+ end
37
+
38
+ World(RepositoryHelper)
39
+
40
+
41
+ Before do
42
+ backup_gitconfigs
43
+ FileUtils.mkdir_p RepositoryHelper::TEST_REPO_DOT_GIT_PATH
44
+ `GIT_DIR=#{RepositoryHelper::TEST_REPO_DOT_GIT_PATH} && git init`
45
+ end
46
+
47
+ After do
48
+ FileUtils.rm_rf RepositoryHelper::TEST_REPO_PATH
49
+ restore_gitconfigs
50
+ end
@@ -0,0 +1,45 @@
1
+ Feature: Switching authors
2
+ In order to indicate which authors are committing
3
+ A user should be able to
4
+ change the currently active pair
5
+
6
+ Scenario: No authors have been added
7
+ When I try to switch to the pair "AA BB"
8
+ Then the last command's output should include "Please add some authors first"
9
+
10
+ Scenario: Pairing with a single author
11
+ Given I have added the author "Linus Torvalds <linus@example.net>"
12
+ When I switch to the pair "LT"
13
+ Then `git pair` should display "Linus Torvalds" for the current author
14
+ And `git pair` should display "linus@example.net" for the current email
15
+
16
+ Scenario: Pairing with two authors
17
+ Given I have added the author "Linus Torvalds <linus@example.net>"
18
+ And I have added the author "Junio C Hamano <junio@example.org>"
19
+ And my global Git configuration is setup with email "devs@example.com"
20
+ When I switch to the pair "LT JCH"
21
+ Then `git pair` should display "Linus Torvalds & Junio C Hamano" for the current author
22
+ And `git pair` should display "lt+jch@example.net" for the current email
23
+
24
+ Scenario: Pairing with two authors the pair email domain is set to the first author
25
+ Given I have added the author "Linus Torvalds <linus@example.net>"
26
+ And I have added the author "Junio C Hamano <junio@example.org>"
27
+ And my global Git configuration is setup with email "devs@example.com"
28
+ When I switch to the pair "JCH LT"
29
+ Then `git pair` should display "Junio C Hamano & Linus Torvalds" for the current author
30
+ And `git pair` should display "jch+lt@example.org" for the current email
31
+
32
+ Scenario: Pairing with a single author and the pair email has been set
33
+ Given I have set the pair email to "devs@widgets.com"
34
+ And I have added the author "Linus Torvalds <linus@example.net>"
35
+ When I switch to the pair "LT"
36
+ Then `git pair` should display "Linus Torvalds" for the current author
37
+ And `git pair` should display "linus@example.net" for the current email
38
+
39
+ Scenario: Pairing with two authors and the pair email has been set
40
+ Given I have set the pair email to "devs@widgets.com"
41
+ And I have added the author "Linus Torvalds <linus@example.net>"
42
+ And I have added the author "Junio C Hamano <junio@example.org>"
43
+ When I switch to the pair "LT JCH"
44
+ Then `git pair` should display "Linus Torvalds & Junio C Hamano" for the current author
45
+ And `git pair` should display "devs+lt+jch@widgets.com" for the current email
data/hooks/post-commit ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This post-commit hook looks for one or more initials inside parentheses at the end of
4
+ # the commit message and uses them to amend the commit author field using the git pair authors
5
+ # matching those initials.
6
+ #
7
+ # To enable this hook, add a symlink to project/.git/hooks/post-commit that points to this file
8
+
9
+ revision, author, body = %x[git log HEAD -1 --format="%H<separator>%an <%ae><separator>%B"].split("<separator>")
10
+
11
+ pair_regex = Regexp.new(/^([^(]*)\(([^)]*)\)$/)
12
+ initials_regex = Regexp.new(/\/|\s|,/)
13
+
14
+ if body.match(pair_regex)
15
+ message = $1.strip # raw commit message without initials
16
+ initials = $2.split(initials_regex)
17
+
18
+ git_pair_author = %x[git pair -s "#{initials.join(' ')}"].chomp
19
+ git_amend_author = %Q(git commit --amend --author="#{git_pair_author}" --message="#{message}")
20
+
21
+ if git_pair_author.empty?
22
+ puts "One or more of the initials: (#{initials.join(',')}) didn't match any of the git pair authors."
23
+ puts "You can use the following command to manually amend the HEAD commit:\n\n"
24
+ puts %Q( git commit --amend --author="First Last & First Last <pair+fl+fl@example.com>"\n\n)
25
+ elsif git_pair_author != author
26
+ puts "Amending revision: #{revision} author from: #{author}"
27
+ puts "To: #{git_pair_author}"
28
+ system(git_amend_author)
29
+ new_sha = %x[git rev-parse HEAD].chomp
30
+ puts "Succeeded! New SHA is: #{new_sha}"
31
+ end
32
+ end
data/lib/git-pair.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "git-pair/version"
2
+
3
+ module GitPair
4
+ autoload :Command, 'git-pair/command'
5
+ autoload :Author, 'git-pair/author'
6
+ autoload :Config, 'git-pair/config'
7
+ autoload :Display, 'git-pair/display'
8
+
9
+ class NoMatchingAuthorsError < ArgumentError; end
10
+ class MissingConfigurationError < RuntimeError; end
11
+ end
@@ -0,0 +1,77 @@
1
+ module GitPair
2
+ class Author
3
+
4
+ ValidAuthorStringRegex = /^\s*([^<]+)<([^>]+)>\s*$/
5
+
6
+ class InvalidAuthorString < TypeError; end
7
+
8
+ def self.all
9
+ Config.all_author_strings.map { |string| new(string) }
10
+ end
11
+
12
+ def self.find_all(abbrs)
13
+ raise MissingConfigurationError, "Please add some authors first" if all.empty?
14
+ abbrs.map { |abbr| self.find(abbr) }
15
+ end
16
+
17
+ def self.find(abbr)
18
+ all.find { |author| author.match?(abbr) } ||
19
+ raise(NoMatchingAuthorsError, "no authors matched #{abbr}")
20
+ end
21
+
22
+ def self.email(authors)
23
+ if authors.length == 1
24
+ authors.first.email
25
+ else
26
+ author_names = authors.map { |a| a.initials }
27
+ if self.authors_prefix
28
+ author_names.unshift(authors_prefix)
29
+ end
30
+ initials_string = author_names.join('+')
31
+ "#{initials_string}@#{authors_email(authors)}"
32
+ end
33
+ end
34
+
35
+ def self.authors_prefix
36
+ return Config.pair_email.split("@").first unless Config.pair_email.empty?
37
+ end
38
+
39
+ def self.authors_email(authors)
40
+ return Config.pair_email.split("@").last unless Config.pair_email.empty?
41
+ return authors.first.email.split("@").last
42
+ end
43
+
44
+ def self.exists?(author)
45
+ self.all.find { |a| a.name == author.name }
46
+ end
47
+
48
+ def self.valid_string?(author_string)
49
+ author_string =~ ValidAuthorStringRegex
50
+ end
51
+
52
+ attr_reader :name, :email
53
+
54
+ def initialize(string)
55
+ unless Author.valid_string?(string)
56
+ raise(InvalidAuthorString, "\"#{string}\" is not a valid name and email")
57
+ end
58
+
59
+ string =~ ValidAuthorStringRegex
60
+ @name = $1.to_s.strip
61
+ @email = $2.to_s.strip
62
+ end
63
+
64
+ def <=>(other)
65
+ name.split.last <=> other.name.split.last
66
+ end
67
+
68
+ def initials
69
+ name.split.map { |word| word[0].chr }.join.downcase
70
+ end
71
+
72
+ def match?(abbr)
73
+ abbr.downcase == initials
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,152 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+ require 'pathname'
4
+
5
+ module GitPair
6
+ module Command
7
+ extend self
8
+
9
+ C_BOLD, C_REVERSE, C_RED, C_RESET = "\e[1m", "\e[7m", "\e[91m", "\e[0m"
10
+
11
+ def run!(args)
12
+ options = OpenStruct.new(:update => true,
13
+ :authors => [])
14
+
15
+ parser = OptionParser.new do |opts|
16
+ opts.banner = highlight('General Syntax:')
17
+ opts.separator ' git pair [reset | authors | options]'
18
+
19
+ opts.separator ' '
20
+ opts.separator highlight('Options:')
21
+
22
+ opts.on '-a', '--add AUTHOR', 'Add an author. Format: "Author Name <author@example.com>"' do |author|
23
+ options.add_author = Author.new(author)
24
+ Config.add_author(options.add_author)
25
+ end
26
+
27
+ opts.on '-r', '--remove NAME', 'Remove an author. Use the full name.' do |name|
28
+ options.remove_author = name
29
+ Config.remove_author options.remove_author
30
+ end
31
+
32
+ opts.on '-d', '--reset', 'Reset current author to default (global) config' do
33
+ options.reset = true
34
+ Config.reset
35
+ end
36
+
37
+ opts.on '--install-hook', 'Install a post-commit hook for the current repo. See git-pair/hooks/post-commit for more information.' do
38
+ options.symlink = true
39
+ end
40
+
41
+ opts.on '--email EMAIL', 'Add a default email address to be used for pairs' do |email|
42
+ puts "Setting email to #{email}"
43
+ options.pair_email = email
44
+ Config.set_pair_email(options.pair_email)
45
+ end
46
+
47
+ opts.on '-s', "--show 'aa [bb]'", 'Show the string to be used for the commit author field' do |initials|
48
+ options.update = false
49
+ options.authors = Author.find_all(initials.split(' '))
50
+ end
51
+
52
+ opts.separator ' '
53
+ opts.separator highlight('Switching authors:')
54
+ opts.separator ' git pair aa [bb] Where AA and BB are any abbreviation of an'
55
+ opts.separator ' '*37 + 'author\'s name. You can specify one or more authors.'
56
+
57
+ opts.separator ' '
58
+ opts.separator highlight('Current config:')
59
+ opts.separator author_list.split("\n")
60
+ opts.separator ' '
61
+ opts.separator pair_email.split("\n")
62
+ opts.separator ' '
63
+ opts.separator current_author_info.split("\n")
64
+ end
65
+
66
+ initials = parser.parse!(args.dup)
67
+
68
+ initials = initials.map { |e| e.split(' ') }.flatten # in case initials are enclosed in quotes
69
+
70
+ if options.authors.empty? && !initials.empty?
71
+ options.authors = Author.find_all(initials)
72
+ end
73
+
74
+ if args.empty?
75
+ puts parser.help
76
+ elsif options.authors && !options.update
77
+ puts Display.git_author options.authors
78
+ elsif options.symlink
79
+ symlink_post_commit_hook
80
+ elsif options.authors.empty?
81
+ puts author_list
82
+ puts
83
+ puts current_author_info
84
+ else
85
+ Config.switch(options.authors)
86
+ puts current_author_info
87
+ end
88
+
89
+ rescue OptionParser::MissingArgument
90
+ abort "missing required argument", parser.help
91
+ rescue OptionParser::InvalidOption, OptionParser::InvalidArgument => e
92
+ abort e.message.sub(':', ''), parser.help
93
+ rescue NoMatchingAuthorsError => e
94
+ abort e.message, "\n" + author_list
95
+ rescue MissingConfigurationError => e
96
+ abort e.message, parser.help
97
+ rescue Author::InvalidAuthorString => e
98
+ abort e.message, parser.help
99
+ end
100
+
101
+ def author_list
102
+ " #{bold 'Author list:'} #{Author.all.sort.map { |a| a.name }.join "\n "}"
103
+ end
104
+
105
+ def pair_email
106
+ " #{bold 'Pair email:'} #{Config.pair_email} \n"
107
+ end
108
+
109
+ def current_author_info
110
+ " #{bold 'Current author:'} #{Config.current_author}\n" +
111
+ " #{bold 'Current email:'} #{Config.current_email}\n "
112
+ end
113
+
114
+ def abort(error_message, extra = "")
115
+ super red(" Error: #{error_message}\n") + extra
116
+ end
117
+
118
+ def highlight(string)
119
+ "#{C_REVERSE}#{string}#{C_RESET}"
120
+ end
121
+
122
+ def bold(string)
123
+ "#{C_BOLD}#{string}#{C_RESET}"
124
+ end
125
+
126
+ def red(string)
127
+ "#{C_RED}#{C_REVERSE}#{string}#{C_RESET}"
128
+ end
129
+
130
+ def symlink_post_commit_hook
131
+ this_directory = Pathname.new File.expand_path(File.dirname(__FILE__))
132
+ post_commit_hook = Pathname.new(File.join(this_directory, "..", "..", "hooks", "post-commit")).realpath
133
+ project_git_hooks = File.join(Dir.pwd, ".git", "hooks")
134
+
135
+ if File.exists?(post_commit_hook) && File.exists?(project_git_hooks)
136
+ symlink_target = Pathname.new(File.join(project_git_hooks, "post-commit"))
137
+
138
+ puts "Symlinking: #{symlink_target}\nto #{post_commit_hook}.\n\n"
139
+
140
+ if File.exists?(symlink_target)
141
+ puts "Can't create symlink! #{symlink_target} already exists."
142
+ else
143
+ symlink_target.make_symlink(post_commit_hook)
144
+ puts "Succceded!"
145
+ end
146
+ elsif !File.exists?(project_git_hooks)
147
+ puts "The current directory doesn't appear to be a valid git repository."
148
+ end
149
+ end
150
+ end
151
+ end
152
+
@@ -0,0 +1,53 @@
1
+ module GitPair
2
+ module Config
3
+ extend self
4
+
5
+ def all_author_strings
6
+ `git config --global --get-all git-pair.authors`.split("\n")
7
+ end
8
+
9
+ def all_author_strings
10
+ `git config --global --get-all git-pair.authors`.split("\n")
11
+ end
12
+
13
+ def add_author(author)
14
+ unless Author.exists?(author)
15
+ `git config --global --add git-pair.authors "#{author.name} <#{author.email}>"`
16
+ end
17
+ end
18
+
19
+ def remove_author(name)
20
+ `git config --global --unset-all git-pair.authors "^#{name} <"`
21
+ `git config --global --remove-section git-pair` if all_author_strings.empty?
22
+ end
23
+
24
+ def switch(authors)
25
+ `git config user.name "#{authors.map { |a| a.name }.join(' & ')}"`
26
+ `git config user.email "#{Author.email(authors)}"`
27
+ end
28
+
29
+ def reset
30
+ `git config --remove-section user`
31
+ end
32
+
33
+ def default_email
34
+ `git config --global --get user.email`.strip
35
+ end
36
+
37
+ def current_author
38
+ `git config --get user.name`.strip
39
+ end
40
+
41
+ def current_email
42
+ `git config --get user.email`.strip
43
+ end
44
+
45
+ def pair_email
46
+ `git config --global --get git-pair.email`.strip
47
+ end
48
+
49
+ def set_pair_email(email)
50
+ `git config --global git-pair.email "#{email}"`
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,9 @@
1
+ module GitPair
2
+ module Display
3
+ extend self
4
+
5
+ def git_author(authors)
6
+ "#{authors.map { |a| a.name }.join(' & ')} <#{Author.email(authors)}>"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module GitPair
2
+ VERSION = "0.3.0"
3
+ end
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: edsinclair-git-pair
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
+ platform: ruby
12
+ authors:
13
+ - Chris Kampmeier
14
+ - Adam McCrea
15
+ - Jon Distad
16
+ - Eirik Dentz Sinclair
17
+ - Tim Gildea
18
+ autorequire:
19
+ bindir: bin
20
+ cert_chain: []
21
+
22
+ date: 2011-08-24 00:00:00 Z
23
+ dependencies:
24
+ - !ruby/object:Gem::Dependency
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ hash: 3
32
+ segments:
33
+ - 0
34
+ version: "0"
35
+ type: :development
36
+ version_requirements: *id001
37
+ name: cucumber
38
+ - !ruby/object:Gem::Dependency
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ name: ruby-debug
52
+ description: A git porcelain for pair programming. Changes git-config's user.name and user.email settings so you can commit as more than one author.
53
+ email:
54
+ - eirik@efficiency20.com
55
+ executables:
56
+ - git-pair
57
+ extensions: []
58
+
59
+ extra_rdoc_files: []
60
+
61
+ files:
62
+ - .autotest
63
+ - .gitignore
64
+ - Gemfile
65
+ - LICENSE
66
+ - README.md
67
+ - Rakefile
68
+ - bin/git-pair
69
+ - config/cucumber.yml
70
+ - edsinclair-git-pair.gemspec
71
+ - features/adding_an_author.feature
72
+ - features/authors.feature
73
+ - features/removing_an_author.feature
74
+ - features/resetting_the_pair.feature
75
+ - features/setting_email_options.feature
76
+ - features/step_definitions/config_steps.rb
77
+ - features/support/env.rb
78
+ - features/switching_authors.feature
79
+ - hooks/post-commit
80
+ - lib/git-pair.rb
81
+ - lib/git-pair/author.rb
82
+ - lib/git-pair/command.rb
83
+ - lib/git-pair/config.rb
84
+ - lib/git-pair/display.rb
85
+ - lib/git-pair/version.rb
86
+ homepage: ""
87
+ licenses: []
88
+
89
+ post_install_message:
90
+ rdoc_options: []
91
+
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 3
100
+ segments:
101
+ - 0
102
+ version: "0"
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ requirements: []
113
+
114
+ rubyforge_project: git-pair
115
+ rubygems_version: 1.8.8
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: Configure git to commit as more than one author
119
+ test_files:
120
+ - features/adding_an_author.feature
121
+ - features/authors.feature
122
+ - features/removing_an_author.feature
123
+ - features/resetting_the_pair.feature
124
+ - features/setting_email_options.feature
125
+ - features/step_definitions/config_steps.rb
126
+ - features/support/env.rb
127
+ - features/switching_authors.feature