gitsu 0.0.1

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/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