gitsu 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +21 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +676 -0
- data/README.md +38 -0
- data/Rakefile +3 -0
- data/TODO +10 -0
- data/bin/git-su +13 -0
- data/bin/git-whoami +13 -0
- data/features/add_user.feature +26 -0
- data/features/change_user_in_different_scopes.feature +24 -0
- data/features/clear_user.feature +28 -0
- data/features/configure_default_scope.feature +9 -0
- data/features/edit_config.feature +8 -0
- data/features/list_users.feature +16 -0
- data/features/print_current_user.feature +60 -0
- data/features/print_options.feature +8 -0
- data/features/step_definitions/gitsu_steps.rb +193 -0
- data/features/support/env.rb +2 -0
- data/features/switch_to_fully_qualified_user.feature +10 -0
- data/features/switch_to_stored_user.feature +49 -0
- data/gitsu.gemspec +19 -0
- data/lib/gitsu.rb +9 -0
- data/lib/gitsu/factory.rb +23 -0
- data/lib/gitsu/git.rb +136 -0
- data/lib/gitsu/gitsu.rb +94 -0
- data/lib/gitsu/runner.rb +18 -0
- data/lib/gitsu/shell.rb +16 -0
- data/lib/gitsu/switcher.rb +94 -0
- data/lib/gitsu/user.rb +55 -0
- data/lib/gitsu/user_file.rb +32 -0
- data/lib/gitsu/user_list.rb +47 -0
- data/lib/gitsu/version.rb +3 -0
- data/man/git-su.1.ronn +120 -0
- data/spec/gitsu/git_spec.rb +189 -0
- data/spec/gitsu/gitsu_spec.rb +177 -0
- data/spec/gitsu/runner_spec.rb +27 -0
- data/spec/gitsu/switcher_spec.rb +196 -0
- data/spec/gitsu/user_list_spec.rb +82 -0
- data/spec/gitsu/user_spec.rb +33 -0
- data/spec/spec_helper.rb +1 -0
- metadata +106 -0
data/lib/gitsu/user.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module GitSu
|
2
|
+
class User
|
3
|
+
NONE = User.new
|
4
|
+
def NONE.to_s
|
5
|
+
"(none)"
|
6
|
+
end
|
7
|
+
def NONE.to_ansi_s(name_color, email_color, reset_color)
|
8
|
+
"#{name_color}(none)#{reset_color}"
|
9
|
+
end
|
10
|
+
|
11
|
+
class ParseError < RuntimeError
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :name, :email
|
15
|
+
|
16
|
+
def User.parse(string)
|
17
|
+
fully_qualified_user_regex = /^[^<]+<[^>]+>$/
|
18
|
+
if string =~ fully_qualified_user_regex
|
19
|
+
name = string[/^[^<]+/].strip
|
20
|
+
email = string[/<.*>/].delete "[<>]"
|
21
|
+
User.new(name, email)
|
22
|
+
else
|
23
|
+
raise ParseError, "Couldn't parse '#{string}' as user (expected user in format: 'John Smith <jsmith@example.com>')"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(name, email)
|
28
|
+
@name, @email = name, email
|
29
|
+
end
|
30
|
+
|
31
|
+
def none?
|
32
|
+
self === NONE
|
33
|
+
end
|
34
|
+
|
35
|
+
def ==(other)
|
36
|
+
eql? other
|
37
|
+
end
|
38
|
+
|
39
|
+
def eql?(other)
|
40
|
+
@name == other.name && @email == other.email
|
41
|
+
end
|
42
|
+
|
43
|
+
def hash
|
44
|
+
to_s.hash
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_ansi_s(name_color, email_color, reset_color)
|
48
|
+
"#{name_color}#{@name}#{reset_color} #{email_color}<#{@email}>#{reset_color}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
to_ansi_s("", "", "")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module GitSu
|
5
|
+
class UserFile
|
6
|
+
def initialize(file_name)
|
7
|
+
@file = file_name
|
8
|
+
unless File.exist? file_name
|
9
|
+
FileUtils.touch file_name
|
10
|
+
end
|
11
|
+
if File.size(file_name) == 0
|
12
|
+
File.open(file_name, "w") do |file|
|
13
|
+
file << "\n"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def write(user)
|
19
|
+
File.open(@file, "a") do |file|
|
20
|
+
file.write "\n#{user.email} : #{user.name}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def read
|
25
|
+
yaml_list = YAML.load_file(@file) or return []
|
26
|
+
yaml_list.map do |email, name|
|
27
|
+
User.new(name, email)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module GitSu
|
2
|
+
class UserList
|
3
|
+
def initialize(file_name)
|
4
|
+
@user_file = UserFile.new(file_name)
|
5
|
+
end
|
6
|
+
|
7
|
+
def add(user)
|
8
|
+
@user_file.write(user)
|
9
|
+
end
|
10
|
+
|
11
|
+
def list
|
12
|
+
@user_file.read
|
13
|
+
end
|
14
|
+
|
15
|
+
def find(search_term)
|
16
|
+
users = @user_file.read
|
17
|
+
matching_users = []
|
18
|
+
match_strategies.each do |strategy|
|
19
|
+
matching_users += users.select { |user| strategy.call(search_term, user) }
|
20
|
+
end
|
21
|
+
matching_users.first || User::NONE
|
22
|
+
end
|
23
|
+
|
24
|
+
def match_strategies
|
25
|
+
[
|
26
|
+
# Whole word of name
|
27
|
+
lambda { |search_term, user| user.name =~ /\b#{search_term}\b/i },
|
28
|
+
|
29
|
+
# Beginning of word in name
|
30
|
+
lambda { |search_term, user| user.name =~ /\b#{search_term}/i },
|
31
|
+
|
32
|
+
# Initials
|
33
|
+
lambda do |search_term, user|
|
34
|
+
initials = user.name.downcase.split(" ").map { |word| word.chars.first }.join
|
35
|
+
initials.include? search_term.downcase
|
36
|
+
end,
|
37
|
+
|
38
|
+
# Segment anywhere in name or email
|
39
|
+
lambda do |search_term, user|
|
40
|
+
name_and_email = "#{user.name} #{user.email}".downcase
|
41
|
+
name_and_email.include? search_term.downcase
|
42
|
+
end
|
43
|
+
]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
data/man/git-su.1.ronn
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
git-su(1) -- Manage your Git Users
|
2
|
+
========================================================
|
3
|
+
|
4
|
+
## SYNOPSIS
|
5
|
+
|
6
|
+
git su [OPTIONS] [user]
|
7
|
+
|
8
|
+
## DESCRIPTION
|
9
|
+
|
10
|
+
Gitsu helps you to manage your projects' Git users.
|
11
|
+
|
12
|
+
* quickly see which user Git will use to commit
|
13
|
+
* quickly switch between Git users
|
14
|
+
* configure a list of Git users to switch between
|
15
|
+
|
16
|
+
## OPTIONS
|
17
|
+
|
18
|
+
-a, --add USER
|
19
|
+
Add a user to the Gitsu users. Should be in the format "John Galt <jgalt@example.com>". You can quickly switch to one of these users by supplying a user argument to git-su.
|
20
|
+
|
21
|
+
-c, --clear
|
22
|
+
Clear all Git users. If a scope (--local, --global, or --system) is specified, only clear that scope's user.
|
23
|
+
|
24
|
+
-e, --edit
|
25
|
+
Open the Gitsu config in an editor. This is the same editor that Git is configured to use for config files.
|
26
|
+
|
27
|
+
-h, --help
|
28
|
+
Show help.
|
29
|
+
|
30
|
+
-l, --local, -g, --global, -s, --system
|
31
|
+
Specify the scope for printing, switching, or clearing selected users.
|
32
|
+
|
33
|
+
-t, --list
|
34
|
+
List the Gitsu users.
|
35
|
+
|
36
|
+
## CONFIGURATION
|
37
|
+
|
38
|
+
Gitsu supports the following configuration options, specified either in Git config files, or by executing `git config`:
|
39
|
+
|
40
|
+
git-su.defaultSelectScope
|
41
|
+
One of "local", "global", or "system" (without quotes). Specifies the default scope that the user is switched in when `git su` is run.
|
42
|
+
|
43
|
+
color.ui
|
44
|
+
Gitsu respects the value of color.ui in the same way Git does. That is, output is colored only if color.ui is set to true, and stdout is a tty.
|
45
|
+
|
46
|
+
## HOMEPAGE
|
47
|
+
|
48
|
+
http://drrb.github.com/gitsu
|
49
|
+
|
50
|
+
## EXAMPLES
|
51
|
+
|
52
|
+
Show current Git users in all scopes
|
53
|
+
|
54
|
+
`$ git su`
|
55
|
+
|
56
|
+
Show the current Git users in specified scopes
|
57
|
+
|
58
|
+
`$ git su --local --global`
|
59
|
+
|
60
|
+
Show the current Git user that Git would use to commit
|
61
|
+
|
62
|
+
`$ git whoami`
|
63
|
+
|
64
|
+
### Adding users
|
65
|
+
|
66
|
+
To add a user to Gitsu (the user will be saved in ~/.gitsu)
|
67
|
+
|
68
|
+
`$ git su --add 'Raphe Rackstraw <rrack@example.com>'`
|
69
|
+
|
70
|
+
You can also add users manually to ~/.gitsu in the following format:
|
71
|
+
|
72
|
+
jporter@example.com: Sir Joseph Porter KCB
|
73
|
+
|
74
|
+
rrack@example.com: Raphe Rackstraw
|
75
|
+
|
76
|
+
### Switching users
|
77
|
+
|
78
|
+
Switch to configured users by initials
|
79
|
+
|
80
|
+
`$ git su jp`
|
81
|
+
|
82
|
+
`Switched to Joseph Porter KCB <jporter@example.com>`
|
83
|
+
|
84
|
+
or by part of their name
|
85
|
+
|
86
|
+
`$ git su straw`
|
87
|
+
|
88
|
+
`Switched to Raphe Rackstraw <rrack@example.com>`
|
89
|
+
|
90
|
+
To clear all Git users
|
91
|
+
|
92
|
+
`$ git su --clear`
|
93
|
+
|
94
|
+
`Clearing all users from Git config`
|
95
|
+
|
96
|
+
### Scopes
|
97
|
+
|
98
|
+
Gitsu supports Git's configuration scopes: local (current repository), global (current OS user), and system (everyone on the system). As in Git, if you don't specify a scope, local scope is assumed.
|
99
|
+
|
100
|
+
To change the user for a specific scope
|
101
|
+
|
102
|
+
`$ git su joe --system`
|
103
|
+
|
104
|
+
`Switched system user to Joseph Porter KCB <jporter@example.com>`
|
105
|
+
|
106
|
+
|
107
|
+
To clear the user for a specific scope
|
108
|
+
|
109
|
+
`$ git su --clear --global`
|
110
|
+
|
111
|
+
`Clearing global user`
|
112
|
+
|
113
|
+
|
114
|
+
## AUTHOR
|
115
|
+
|
116
|
+
drrb at the git hub
|
117
|
+
|
118
|
+
## SEE ALSO
|
119
|
+
|
120
|
+
git(1), git-config(1).
|
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module GitSu
|
4
|
+
describe Git do
|
5
|
+
let(:shell) { double('shell') }
|
6
|
+
let(:git) { CachingGit.new(shell) }
|
7
|
+
|
8
|
+
describe '#select_user' do
|
9
|
+
it 'switches to the specified user' do
|
10
|
+
shell.should_receive(:execute).with("git config --global user.name 'John Galt'").and_return true
|
11
|
+
shell.should_receive(:execute).with("git config --global user.email 'jgalt@example.com'").and_return true
|
12
|
+
git.select_user User.new("John Galt", "jgalt@example.com"), :global
|
13
|
+
end
|
14
|
+
it 'escapes apostrophes' do
|
15
|
+
shell.should_receive(:execute).with("git config --global user.name 'John O'\\''Grady'").and_return true
|
16
|
+
shell.should_receive(:execute).with("git config --global user.email 'jo@example.com'").and_return true
|
17
|
+
git.select_user User.new("John O'Grady", "jo@example.com"), :global
|
18
|
+
end
|
19
|
+
it "raises an exception when can't set the name" do
|
20
|
+
shell.should_receive(:execute).with("git config --global user.name 'John O'\\''Grady'").and_return(false)
|
21
|
+
expect {git.select_user User.new("John O'Grady", "jo@example.com"), :global}.to raise_error(Git::ConfigSettingError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#selected_user' do
|
26
|
+
context 'when a scope is specified' do
|
27
|
+
context 'when a user is selected' do
|
28
|
+
it 'returns the current user' do
|
29
|
+
shell.should_receive(:capture).with("git config --global user.name").and_return("John Galt")
|
30
|
+
shell.should_receive(:capture).with("git config --global user.email").and_return("jgalt@example.com")
|
31
|
+
git.selected_user(:global).should == User.new("John Galt", "jgalt@example.com")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when no user is selected' do
|
36
|
+
it 'returns the null user' do
|
37
|
+
shell.should_receive(:capture).with("git config --global user.name").and_return("")
|
38
|
+
git.selected_user(:global).should be User::NONE
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when "derived" scope is specified' do
|
44
|
+
it 'returns the current user derived by git' do
|
45
|
+
shell.should_receive(:capture).with("git config user.name").and_return("John Galt")
|
46
|
+
shell.should_receive(:capture).with("git config user.email").and_return("jgalt@example.com")
|
47
|
+
git.selected_user(:derived).should == User.new("John Galt", "jgalt@example.com")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "caches the result" do
|
52
|
+
shell.should_receive(:capture).with("git config user.name").and_return("John Galt")
|
53
|
+
shell.should_receive(:capture).with("git config user.email").and_return("jgalt@example.com")
|
54
|
+
git.selected_user(:derived).should == User.new("John Galt", "jgalt@example.com")
|
55
|
+
git.selected_user(:derived).should == User.new("John Galt", "jgalt@example.com")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#edit_gitsu_config' do
|
60
|
+
it 'opens the Gitsu config in an editor' do
|
61
|
+
shell.should_receive(:execute).with("git config --edit --file #{File.expand_path '~/.gitsu'}")
|
62
|
+
git.edit_gitsu_config
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#color_output?' do
|
67
|
+
context 'when Git says to use colorize output' do
|
68
|
+
it 'returns true' do
|
69
|
+
shell.should_receive(:execute).with("git config --get-colorbool color.ui").and_return true
|
70
|
+
git.color_output?.should be true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when git says not to colorize output' do
|
75
|
+
it 'returns true' do
|
76
|
+
shell.should_receive(:execute).with("git config --get-colorbool color.ui").and_return false
|
77
|
+
git.color_output?.should be false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it "caches the result" do
|
82
|
+
shell.should_receive(:execute).with("git config --get-colorbool color.ui").and_return false
|
83
|
+
git.color_output?.should be false
|
84
|
+
git.color_output?.should be false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#clear_user' do
|
89
|
+
context "when there's other user config" do
|
90
|
+
it 'clears the current user in the specified scope' do
|
91
|
+
shell.should_receive(:capture).with("git config --local user.name").and_return("John Smith")
|
92
|
+
shell.should_receive(:capture).with("git config --local user.email").and_return("js@example.com")
|
93
|
+
shell.should_receive(:capture).with("git config --local --unset user.name").and_return("")
|
94
|
+
shell.should_receive(:capture).with("git config --local --unset user.email").and_return("")
|
95
|
+
shell.should_receive(:capture).with("git config --local --list").and_return("ui.color=true\nuser.signingkey = something\nsomething.else")
|
96
|
+
git.clear_user(:local)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
context "when there's no other user config" do
|
100
|
+
it 'quietly attempts to remove the user section of the config in the specified scope' do
|
101
|
+
shell.should_receive(:capture).with("git config --system user.name").and_return("John Smith")
|
102
|
+
shell.should_receive(:capture).with("git config --system user.email").and_return("js@example.com")
|
103
|
+
shell.should_receive(:capture).with("git config --system --unset user.name").and_return("")
|
104
|
+
shell.should_receive(:capture).with("git config --system --unset user.email").and_return("")
|
105
|
+
shell.should_receive(:capture).with("git config --system --list").and_return("")
|
106
|
+
shell.should_receive(:capture).with("git config --system --remove-section user 2>/dev/null").and_return("")
|
107
|
+
git.clear_user(:system)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
context "when no user is selected" do
|
111
|
+
it "doesn't attempt to clear the user" do
|
112
|
+
shell.should_receive(:capture).with("git config --system user.name").and_return("")
|
113
|
+
git.clear_user :system
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#get_color' do
|
119
|
+
it 'gets an ANSI escape code from Git for the specified color' do
|
120
|
+
shell.should_receive(:capture).with("git config --get-color '' 'on blue'").and_return("xxx")
|
121
|
+
color = git.get_color("on blue")
|
122
|
+
color.should == "xxx"
|
123
|
+
end
|
124
|
+
it 'caches colors' do
|
125
|
+
shell.should_receive(:capture).with("git config --get-color '' 'on green'").and_return("xxx")
|
126
|
+
git.get_color("on green").should == "xxx"
|
127
|
+
git.get_color("on green").should == "xxx"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '#render' do
|
132
|
+
context "when Git says to color output" do
|
133
|
+
it "colors the user output" do
|
134
|
+
user = User.new('John Galt', 'jgalt@example.com')
|
135
|
+
|
136
|
+
git.should_receive(:color_output?).and_return true
|
137
|
+
git.should_receive(:get_color).with("blue").and_return "__blue__"
|
138
|
+
git.should_receive(:get_color).with("green").and_return "__green__"
|
139
|
+
git.should_receive(:get_color).with("reset").and_return "__reset__"
|
140
|
+
|
141
|
+
git.render(user).should == "__blue__John Galt__reset__ __green__<jgalt@example.com>__reset__"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when Git says not to color output" do
|
146
|
+
it "calls to_s() on the user" do
|
147
|
+
user = User.new('John Galt', 'jgalt@example.com')
|
148
|
+
|
149
|
+
git.should_receive(:color_output?).and_return false
|
150
|
+
|
151
|
+
git.render(user).should == user.to_s
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "#render_user" do
|
157
|
+
it "is equivalent to calling #render(#selected_user(scope))" do
|
158
|
+
shell.should_receive(:capture).with("git config --local user.name").and_return("John Smith")
|
159
|
+
shell.should_receive(:capture).with("git config --local user.email").and_return("js@example.com")
|
160
|
+
shell.should_receive(:execute).with("git config --get-colorbool color.ui").and_return true
|
161
|
+
shell.should_receive(:capture).with("git config --get-color '' 'blue'").and_return("*")
|
162
|
+
shell.should_receive(:capture).with("git config --get-color '' 'green'").and_return("?")
|
163
|
+
shell.should_receive(:capture).with("git config --get-color '' 'reset'").and_return("!")
|
164
|
+
git.render_user(:local).should == "*John Smith! ?<js@example.com>!"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "#default_select_scope" do
|
169
|
+
context "when a default selecton scope is configured" do
|
170
|
+
it "returns the configured default scope" do
|
171
|
+
shell.should_receive(:capture).with("git config git-su.defaultSelectScope").and_return("global")
|
172
|
+
git.default_select_scope.should == :global
|
173
|
+
end
|
174
|
+
end
|
175
|
+
context "when no default selection scope is configured" do
|
176
|
+
it "returns the conventional default scope (local)" do
|
177
|
+
shell.should_receive(:capture).with("git config git-su.defaultSelectScope").and_return("")
|
178
|
+
git.default_select_scope.should == :local
|
179
|
+
end
|
180
|
+
end
|
181
|
+
context "when an invalid default selection scope is configured" do
|
182
|
+
it "dies noisily" do
|
183
|
+
shell.should_receive(:capture).with("git config git-su.defaultSelectScope").and_return("xxxxxx")
|
184
|
+
expect {git.default_select_scope}.to raise_error(Git::InvalidConfigError)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|