gas 0.1.8 → 1.0.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/bin/gas +70 -35
- data/bin/gas-add +7 -0
- data/bin/gas-delete +7 -0
- data/bin/gas-import +7 -0
- data/bin/gas-list +6 -0
- data/bin/gas-show +6 -0
- data/bin/gas-use +7 -0
- data/lib/gas.rb +67 -103
- data/lib/gas/git_config.rb +25 -0
- data/lib/gas/user.rb +11 -4
- data/lib/gas/users.rb +110 -0
- data/lib/gas/version.rb +2 -3
- data/spec/integration/gas_spec.rb +118 -0
- data/spec/integration/users_spec.rb +40 -0
- data/spec/spec_helper.rb +10 -141
- data/spec/unit/git_config_spec.rb +82 -0
- data/spec/unit/user_spec.rb +18 -0
- data/spec/unit/users_spec.rb +71 -0
- metadata +23 -112
- data/lib/gas/config.rb +0 -148
- data/lib/gas/gitconfig.rb +0 -46
- data/lib/gas/github_speaker.rb +0 -219
- data/lib/gas/prompter.rb +0 -169
- data/lib/gas/settings.rb +0 -28
- data/lib/gas/ssh.rb +0 -305
- data/spec/integration/ssh_spec.rb +0 -338
- data/spec/unit/config_spec.rb +0 -83
- data/spec/unit/gitconfig_spec.rb +0 -85
- data/spec/unit/github_speaker_spec.rb +0 -107
- data/spec/unit/settings_spec.rb +0 -56
data/lib/gas/users.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Gas
|
4
|
+
|
5
|
+
# Class that keeps track of users
|
6
|
+
class Users
|
7
|
+
attr_reader :users
|
8
|
+
|
9
|
+
# Initializes the object. If no users are supplied we look for a config file, if none then create it, and parse it to load users
|
10
|
+
# @param [String] config_file The path to the file that stores users
|
11
|
+
def initialize(config_file)
|
12
|
+
@config_file = config_file
|
13
|
+
@users = []
|
14
|
+
|
15
|
+
setup!
|
16
|
+
end
|
17
|
+
|
18
|
+
# Checks if a user with _nickname_ exists
|
19
|
+
# @param [String] nickname
|
20
|
+
# @return [Boolean]
|
21
|
+
def exists?(nickname)
|
22
|
+
users.each do |user|
|
23
|
+
if user.nickname == nickname
|
24
|
+
return true;
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the user with nickname nil if no such user exists
|
32
|
+
# @param [String|Symbol] nickname
|
33
|
+
# @return [User|nil]
|
34
|
+
def get(nickname)
|
35
|
+
users.each do |user|
|
36
|
+
if user.nickname == nickname.to_s
|
37
|
+
return user
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# Override [] to get hash style acces to users
|
45
|
+
# @param [String|Symbol] nickname
|
46
|
+
# @return [User|nil]
|
47
|
+
def [](nickname)
|
48
|
+
get nickname
|
49
|
+
end
|
50
|
+
|
51
|
+
# Adds a user
|
52
|
+
# @param [User]
|
53
|
+
def add(user)
|
54
|
+
@users << user
|
55
|
+
end
|
56
|
+
|
57
|
+
# Deletes a user by nickname
|
58
|
+
# @param [String] nickname The nickname of the user to delete
|
59
|
+
def delete(nickname)
|
60
|
+
@users.delete_if do |user|
|
61
|
+
user.nickname == nickname
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Saves the current users to the config file
|
66
|
+
def save!
|
67
|
+
File.open @config_file, 'w' do |file|
|
68
|
+
file.write self
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Override to_s to output correct format
|
73
|
+
def to_s
|
74
|
+
current_user = GitConfig.current_user
|
75
|
+
users.map do |user|
|
76
|
+
if current_user == user
|
77
|
+
" ==> #{user.to_s[5,user.to_s.length]}"
|
78
|
+
else
|
79
|
+
user.to_s
|
80
|
+
end
|
81
|
+
end.join "\n"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Run the setup steps
|
85
|
+
def setup!
|
86
|
+
ensure_config_directory_exists!
|
87
|
+
load_config
|
88
|
+
load_users
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def ensure_config_directory_exists!
|
94
|
+
unless File.exists? File.dirname(@config_file)
|
95
|
+
Dir::mkdir File.dirname(@config_file)
|
96
|
+
FileUtils.touch @config_file
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def load_config
|
101
|
+
@config = File.read @config_file
|
102
|
+
end
|
103
|
+
|
104
|
+
def load_users
|
105
|
+
@config.scan(/\[(.+)\]\s+name = (.+)\s+email = (.+)/) do |nickname, name, email|
|
106
|
+
@users << User.new(name, email, nickname)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/gas/version.rb
CHANGED
@@ -0,0 +1,118 @@
|
|
1
|
+
require './spec/spec_helper'
|
2
|
+
|
3
|
+
require './lib/gas'
|
4
|
+
|
5
|
+
describe Gas do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should show correct version' do
|
12
|
+
output = capture_stdout { Gas.print_version }
|
13
|
+
output.should == "#{Gas::VERSION}\n"
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should show correct usage' do
|
17
|
+
output = capture_stdout { Gas.print_usage }
|
18
|
+
output.should == "Usage: command [parameters]\n\nBuilt-in commands:\n add NICKNAME NAME EMAIL - adds a new user to gas\n delete NICKNAME - deletes a user from gas\n import NICKNAME - imports the user from .gitconfig into NICKNAME\n list - lists all users\n show - shows the current user\n use NICKNAME - sets the user with NICKNAME as the current user\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return if correct number of params is supplied' do
|
22
|
+
mock(ARGV).length { 3 }
|
23
|
+
lambda { Gas.check_parameters( 3, 'Nope') }.should_not raise_error SystemExit
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should exit if incorrect number of params is supplied' do
|
27
|
+
mock(ARGV).length { 3 }
|
28
|
+
lambda { Gas.check_parameters( 4, 'Error message') }.should raise_error SystemExit
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should list users' do
|
32
|
+
any_instance_of(Gas::Users) do |u|
|
33
|
+
stub(u).to_s { 'users' }
|
34
|
+
end
|
35
|
+
output = capture_stdout { Gas.list }
|
36
|
+
output.should == "\nAvailable users:\n\nusers\n\n"
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should show current user if any' do
|
40
|
+
mock(Gas::GitConfig).current_user { Gas::User.new('foo', 'bar') }
|
41
|
+
output = capture_stdout { Gas.show }
|
42
|
+
output.should == "Current user:\nfoo <bar>\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should show current user if any' do
|
46
|
+
mock(Gas::GitConfig).current_user { nil }
|
47
|
+
output = capture_stdout { Gas.show }
|
48
|
+
output.should == "No current user in gitconfig\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should exit if no user by nickname exists' do
|
52
|
+
any_instance_of(Gas::Users) do |u|
|
53
|
+
stub(u).exists?('foo') { false }
|
54
|
+
end
|
55
|
+
lambda { Gas.use('foo').should be_false }.should raise_error SystemExit
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should use given user' do
|
59
|
+
user = Gas::User.new('foo bar', 'foo@bar.com', 'foo')
|
60
|
+
any_instance_of(Gas::Users) do |u|
|
61
|
+
stub(u).exists?('foo') { true }
|
62
|
+
stub(u).get('foo') { user }
|
63
|
+
end
|
64
|
+
mock(Gas::GitConfig).change_user(user) { }
|
65
|
+
mock(Gas::GitConfig).current_user { user }
|
66
|
+
|
67
|
+
output = capture_stdout { Gas.use('foo') }
|
68
|
+
output.should == "Current user:\nfoo bar <foo@bar.com>\n"
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should add new user' do
|
72
|
+
any_instance_of(Gas::Users) do |u|
|
73
|
+
stub(u).exists?('foo') { false }
|
74
|
+
stub(u).save! { }
|
75
|
+
end
|
76
|
+
output = capture_stdout { Gas.add('foo', 'foo bar', 'foo@bar.com') }
|
77
|
+
output.should == "Added new author\n [foo]\n name = foo bar\n email = foo@bar.com\n"
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should not add new user if nickname exists' do
|
81
|
+
any_instance_of(Gas::Users) do |u|
|
82
|
+
stub(u).exists?('foo') { true }
|
83
|
+
end
|
84
|
+
lambda { Gas.add('foo', 'foo bar', 'foo@bar.com') }.should raise_error SystemExit
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should delete user if nickname exists' do
|
88
|
+
any_instance_of(Gas::Users) do |u|
|
89
|
+
stub(u).save! { }
|
90
|
+
end
|
91
|
+
Gas.add('bar', 'foo bar', 'foo@bar.com')
|
92
|
+
output = capture_stdout { Gas.delete('bar') }
|
93
|
+
output.should == "Deleted author bar\n"
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should import current_user to gas' do
|
97
|
+
user = Gas::User.new('foo bar', 'foo@bar.com')
|
98
|
+
any_instance_of(Gas::Users) do |u|
|
99
|
+
stub(u).exists?('foo') { false }
|
100
|
+
stub(u).save! { }
|
101
|
+
end
|
102
|
+
mock(Gas::GitConfig).current_user { user }
|
103
|
+
|
104
|
+
output = capture_stdout { Gas.import('foo') }
|
105
|
+
output.should == "Imported author\n [foo]\n name = foo bar\n email = foo@bar.com\n"
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should not import current_user to gas if no current_user exists' do
|
109
|
+
any_instance_of(Gas::Users) do |u|
|
110
|
+
stub(u).exists?('foo') { false }
|
111
|
+
end
|
112
|
+
mock(Gas::GitConfig).current_user { nil }
|
113
|
+
|
114
|
+
output = capture_stdout { Gas.import('foo') }
|
115
|
+
output.should == "No current user to import\n"
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require './spec/spec_helper'
|
2
|
+
|
3
|
+
require './lib/gas'
|
4
|
+
|
5
|
+
describe Gas::Users do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
@name = 'Fredrik Wallgren'
|
9
|
+
@email = 'fredrik.wallgren@gmail.com'
|
10
|
+
@nickname = 'walle'
|
11
|
+
@dir = File.join(Dir.tmpdir, "gas_#{rand(42000000-100000) + 10000}")
|
12
|
+
@file_path = File.join(@dir, 'gas_users')
|
13
|
+
@users = Gas::Users.new @file_path
|
14
|
+
end
|
15
|
+
|
16
|
+
after :each do
|
17
|
+
File.delete @file_path
|
18
|
+
Dir.delete @dir
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should be able to parse users from users format' do
|
22
|
+
users = "[#{@nickname}]\n name = #{@name}\n email = #{@email}\n\n[user2]\n name = foo\n email = bar"
|
23
|
+
file = File.new(@file_path, "w")
|
24
|
+
file.puts users
|
25
|
+
file.close
|
26
|
+
@users = Gas::Users.new @file_path
|
27
|
+
@users.users.count.should be 2
|
28
|
+
@users.users[0].name.should eq @name
|
29
|
+
@users.users[0].email.should eq @email
|
30
|
+
@users.users[0].nickname.should eq @nickname
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should be able to save the config' do
|
34
|
+
@users.users.count.should be 0
|
35
|
+
@users.add Gas::User.new('Foo Bar', 'foo@bar.com', 'foobar')
|
36
|
+
@users.save!
|
37
|
+
@users = Gas::Users.new @file_path
|
38
|
+
@users.users.count.should be 1
|
39
|
+
end
|
40
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,37 +1,16 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require 'tempfile'
|
4
|
+
|
3
5
|
if ENV['COVERAGE']
|
4
6
|
require 'simplecov'
|
5
7
|
SimpleCov.start
|
6
8
|
end
|
7
9
|
|
8
|
-
require 'fileutils'
|
9
|
-
include FileUtils
|
10
|
-
|
11
|
-
# Create a virtual directory in the tmp folder so
|
12
|
-
# we don't risk damaging files on the running machine
|
13
|
-
fake_home = '/tmp/gas-virtual-fs'
|
14
|
-
rm_rf fake_home if File.exists? fake_home
|
15
|
-
mkdir_p fake_home
|
16
|
-
mkdir_p fake_home + '/.ssh'
|
17
|
-
ENV['HOME'] = fake_home
|
18
|
-
|
19
|
-
|
20
10
|
RSpec.configure do |config|
|
21
11
|
config.mock_with :rr
|
22
12
|
end
|
23
13
|
|
24
|
-
# Configure VCR, this thing alows you to record HTTP traffic so you never
|
25
|
-
# Need to connect to a server. Tests run offline just fine!
|
26
|
-
require 'vcr'
|
27
|
-
|
28
|
-
VCR.configure do |c|
|
29
|
-
#c.allow_http_connections_when_no_cassette = true # set to true if you're refreshing the cassets in fixtures
|
30
|
-
c.cassette_library_dir = 'fixtures/vcr_cassettes'
|
31
|
-
c.hook_into :webmock # or :fakeweb
|
32
|
-
end
|
33
|
-
|
34
|
-
|
35
14
|
# Mocks a cli call using ` with rr.
|
36
15
|
# Takes a block to use as rr return block
|
37
16
|
# @param [Object] mock_object The object to mock
|
@@ -41,123 +20,13 @@ def mock_cli_call(mock_object, command)
|
|
41
20
|
mock(mock_object).__double_definition_create__.call(:`, command) { yield }
|
42
21
|
end
|
43
22
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
if File.exists?(SSH_DIRECTORY + "/id_rsa.pub")
|
50
|
-
File.delete(SSH_DIRECTORY + "/id_rsa.pub")
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
def restore_the_testers_ssh_key
|
56
|
-
if File.exists?(GAS_DIRECTORY + "/temp_test")
|
57
|
-
@pattern_to_restore_privl = File.open(GAS_DIRECTORY + "/temp_test","r").read # this test requires some juggling of files that may already exist.
|
58
|
-
File.open(SSH_DIRECTORY + "/id_rsa","w+").puts @pattern_to_restore_privl
|
59
|
-
File.delete(GAS_DIRECTORY + "/temp_test")
|
60
|
-
end
|
61
|
-
|
62
|
-
if File.exists?(GAS_DIRECTORY + "/temp_test.pub")
|
63
|
-
@pattern_to_restore_publ = File.open(GAS_DIRECTORY + "/temp_test.pub","r").read # We don't want to mess things up for the tester, so we will need to save these files and then delete them
|
64
|
-
File.open(SSH_DIRECTORY + "/id_rsa.pub","w+").puts @pattern_to_restore_publ
|
65
|
-
File.delete(GAS_DIRECTORY + "/temp_test.pub")
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def clean_out_gas_directory(nickname)
|
70
|
-
if File.exists?(GAS_DIRECTORY + "/#{nickname}_id_rsa")
|
71
|
-
File.delete(GAS_DIRECTORY + "/#{nickname}_id_rsa")
|
72
|
-
end
|
73
|
-
|
74
|
-
if File.exists?(SSH_DIRECTORY + "/#{nickname}_id_rsa.pub")
|
75
|
-
File.delete(@ssh_dir + "/#{nickname}_id_rsa.pub")
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# this function either mutates an existing file, or creates a new file that won't
|
80
|
-
# have been backed up by gas
|
81
|
-
def plant_bogus_rsa_keys_in_ssh_directory
|
82
|
-
id_rsa = "this rsa file is bogus and not backed up by .gas yet"
|
83
|
-
id_rsa_pub = "this pub rsa file is bogus and not backed up by .gas yet"
|
84
|
-
|
85
|
-
File.open(SSH_DIRECTORY + "/id_rsa","w+") do |f|
|
86
|
-
f.puts id_rsa
|
87
|
-
end
|
88
|
-
|
89
|
-
File.open(SSH_DIRECTORY + "/id_rsa.pub","w+") do |f|
|
90
|
-
f.puts id_rsa_pub
|
91
|
-
end
|
92
|
-
|
93
|
-
return [id_rsa, id_rsa_pub]
|
94
|
-
end
|
95
|
-
|
96
|
-
|
97
|
-
def create_user_no_git(nickname, name, email)
|
98
|
-
Gas::Prompter.stub!(:user_wants_gas_to_handle_rsa_keys?).and_return(true)
|
99
|
-
#Gas::Ssh.stub!(:user_wants_to_use_key_already_in_ssh?).and_return(false)
|
100
|
-
Gas::Prompter.stub!(:user_wants_to_install_key_to_github?).and_return(false)
|
101
|
-
|
102
|
-
Gas.add(nickname,name,email)
|
103
|
-
|
104
|
-
Gas::Prompter.unstub!(:user_wants_gas_to_handle_rsa_keys?)
|
105
|
-
#Gas::Ssh.unstub!(:user_wants_to_use_key_already_in_ssh?)
|
106
|
-
Gas::Prompter.unstub!(:user_wants_to_install_key_to_github?)
|
107
|
-
end
|
108
|
-
|
109
|
-
# toasts ssh keys for a given nickname and removal from gas.authors
|
110
|
-
def delete_user_no_git(nickname)
|
111
|
-
Gas.delete(nickname)
|
112
|
-
end
|
113
|
-
|
114
|
-
# Cycles through github, looking to see if rsa exists as a public key, then deletes it if it does
|
115
|
-
def remove_key_from_github_account(username, password, rsa)
|
116
|
-
# get all keys
|
117
|
-
keys = Gas::Ssh.get_keys(username, password)
|
118
|
-
# loop through arrays checking against 'key'
|
119
|
-
keys.each do |key|
|
120
|
-
if key["key"] == rsa
|
121
|
-
return Gas::Ssh.remove_key_by_id!(username, password, key["id"])
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
return false # key not found
|
126
|
-
end
|
127
|
-
|
128
|
-
def delete_all_keys_in_github_account!(github_speaker)
|
129
|
-
VCR.use_cassette('delete_all_keys_in_github_account', :record => :new_episodes) do
|
130
|
-
github_speaker.keys.each do |key|
|
131
|
-
Gas::GithubSpeaker.publicize_methods do
|
132
|
-
github_speaker.remove_key_by_id! key['id']
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def get_keys(username, password)
|
139
|
-
server = 'api.github.com'
|
140
|
-
path = '/user/keys'
|
141
|
-
|
142
|
-
http = Net::HTTP.new(server,443)
|
143
|
-
req = Net::HTTP::Get.new(path)
|
144
|
-
http.use_ssl = true
|
145
|
-
req.basic_auth username, password
|
146
|
-
response = http.request(req)
|
147
|
-
|
148
|
-
return JSON.parse(response.body)
|
149
|
-
end
|
150
|
-
|
151
|
-
def count_of_files_in(directory_path)
|
152
|
-
Dir.glob(File.join(directory_path, '**', '*')).select { |file| File.file?(file) }.count
|
153
|
-
end
|
154
|
-
|
155
|
-
# This is used for publicizing the methods of a class so you can use TDD for projects, even in RUBY!
|
156
|
-
class Class
|
157
|
-
def publicize_methods
|
158
|
-
saved_private_instance_methods = self.private_instance_methods
|
159
|
-
self.class_eval { public(*saved_private_instance_methods) }
|
23
|
+
def capture_stdout(&block)
|
24
|
+
original_stdout = $stdout
|
25
|
+
$stdout = fake = StringIO.new
|
26
|
+
begin
|
160
27
|
yield
|
161
|
-
|
28
|
+
ensure
|
29
|
+
$stdout = original_stdout
|
162
30
|
end
|
163
|
-
|
31
|
+
fake.string
|
32
|
+
end
|