gitsu 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+
@@ -0,0 +1,3 @@
1
+ module GitSu
2
+ VERSION = "0.0.1"
3
+ end
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