diff --git a/README.md b/README.md index e61879d..96b28bf 100644 --- a/README.md +++ b/README.md @@ -23,33 +23,36 @@ After you've [installed](#installation) `gh-auth`, you can give me ssh access with: ```bash -$ gh-auth add chrishunt +$ gh-auth --add chrishunt Adding 2 key(s) to '/Users/chris/.ssh/authorized_keys' ``` That was easy! When we're done working, you can revoke my access with: ```bash -$ gh-auth remove chrishunt +$ gh-auth --remove chrishunt Removing 2 key(s) from '/Users/chris/.ssh/authorized_keys' ``` You can add and remove any number of users at the same time. ```bash -$ gh-auth add chrishunt zachmargolis +$ gh-auth --add chrishunt,zachmargolis Adding 4 key(s) to '/Users/chris/.ssh/authorized_keys' -$ gh-auth list +$ gh-auth --list Added users: chrishunt, zachmargolis -$ gh-auth remove chrishunt +$ gh-auth --remove chrishunt Removing 2 key(s) from '/Users/chris/.ssh/authorized_keys' -$ gh-auth remove zachmargolis +$ gh-auth --list +Added users: zachmargolis + +$ gh-auth --remove zachmargolis Removing 2 key(s) from '/Users/chris/.ssh/authorized_keys' -$ gh-auth list +$ gh-auth --list Added users: ``` @@ -78,7 +81,13 @@ Added users: `gh-auth` can be used from the command line after the gem has been installed. ```bash -usage: gh-auth [--version] [add|remove|list] +usage: gh-auth [--version] [--list] [--add|--remove] + +options: + --add doug,sally Add GitHub users + --remove doug,sally Remove GitHub users + --list List all GitHub users added + --version Show version ``` ### In Your Project @@ -90,14 +99,10 @@ too. require 'github/auth' # Add keys for GitHub user 'chrishunt' -Github::Auth::CLI.new(%w( - add chrishunt -)).execute +Github::Auth::CLI.new.execute %w(--add chrishunt) # Remove keys for GitHub user 'chrishunt' -Github::Auth::CLI.new(%w( - remove chrishunt -)).execute +Github::Auth::CLI.new.execute %w(--remove chrishunt) ``` ## Installation @@ -108,7 +113,13 @@ Install the `github-auth` gem: $ gem install github-auth $ gh-auth -usage: gh-auth [--version] [add|remove|list] +usage: gh-auth [--version] [--list] [--add|--remove] + +options: + --add doug,sally Add GitHub users + --remove doug,sally Remove GitHub users + --list List all GitHub users added + --version Show version ``` ### SSH Public Key Authentication (Mac OS X) @@ -136,7 +147,7 @@ First, authorize yourself for ssh. (Make sure to replace 'chrishunt' with *your* GitHub username) ```bash -$ gh-auth add chrishunt +$ gh-auth --add chrishunt Adding 2 key(s) to '/Users/chris/.ssh/authorized_keys' ``` @@ -152,7 +163,7 @@ $ ssh -o PreferredAuthentications=publickey localhost Next, remove your public keys from the keys file: ```bash -$ gh-auth remove chrishunt +$ gh-auth --remove chrishunt Removing 2 key(s) from '/Users/chris/.ssh/authorized_keys' ``` diff --git a/Rakefile b/Rakefile index b72d6de..b6bb574 100644 --- a/Rakefile +++ b/Rakefile @@ -12,6 +12,7 @@ desc 'Check code quality' Cane::RakeTask.new(:quality) do |task| task.abc_max = 9 task.use Cane::HashCheck + task.abc_exclude = %w(Auth::Options#initialize) end task default: :spec diff --git a/bin/gh-auth b/bin/gh-auth index db5362d..ecf0893 100755 --- a/bin/gh-auth +++ b/bin/gh-auth @@ -2,4 +2,4 @@ require 'github/auth' -Github::Auth::CLI.new(ARGV).execute +Github::Auth::CLI.new.execute(ARGV) diff --git a/lib/github/auth.rb b/lib/github/auth.rb index 37946e2..cd4b159 100644 --- a/lib/github/auth.rb +++ b/lib/github/auth.rb @@ -2,4 +2,5 @@ require 'github/auth/key' require 'github/auth/keys_client' require 'github/auth/keys_file' +require 'github/auth/options' require 'github/auth/cli' diff --git a/lib/github/auth/cli.rb b/lib/github/auth/cli.rb index 81a486a..f5ecb69 100644 --- a/lib/github/auth/cli.rb +++ b/lib/github/auth/cli.rb @@ -1,43 +1,21 @@ module Github::Auth # Command Line Interface for parsing and executing commands class CLI - attr_reader :command, :usernames + attr_reader :options - COMMANDS = %w(add remove list) - - def initialize(argv) - @command = argv.shift - @usernames = argv - end - - def execute - if COMMANDS.include?(command) - send command - elsif command == '--version' - print_version - else - print_usage - end + def execute(args) + @options = Options.new.parse(args) + send options.command end private def add - if usernames.empty? - print_usage - return - end - on_keys_file :write!, "Adding #{keys.count} key(s) to '#{keys_file.path}'" end def remove - if usernames.empty? - print_usage - return - end - on_keys_file :delete!, "Removing #{keys.count} key(s) from '#{keys_file.path}'" end @@ -46,6 +24,14 @@ def list puts "Added users: #{keys_file.github_users.join(', ')}" end + def version + puts Github::Auth::VERSION + end + + def usage + puts options.usage + end + def on_keys_file(action, message) puts message rescue_keys_file_errors { keys_file.send action, keys } @@ -54,26 +40,10 @@ def on_keys_file(action, message) def rescue_keys_file_errors yield rescue KeysFile::PermissionDeniedError - print_permission_denied - rescue KeysFile::FileDoesNotExistError - print_file_does_not_exist - end - - def print_usage - puts "usage: gh-auth [--version] [#{COMMANDS.join '|'}] " - end - - def print_version - puts "gh-auth version #{Github::Auth::VERSION}" - end - - def print_permission_denied puts 'Permission denied!' puts puts "Make sure you have write permissions for '#{keys_file.path}'" - end - - def print_file_does_not_exist + rescue KeysFile::FileDoesNotExistError puts "Keys file does not exist!" puts puts "Create one now and try again:" @@ -81,18 +51,8 @@ def print_file_does_not_exist puts " $ touch #{keys_file.path}" end - def print_github_user_does_not_exist(username) - puts "Github user '#{username}' does not exist" - end - - def print_github_unavailable - puts "Github appears to be unavailable :(" - puts - puts "https://status.github.com" - end - def keys - @keys ||= usernames.map { |username| keys_for username }.flatten.compact + @keys ||= options.usernames.map { |user| keys_for user }.flatten.compact end def keys_for(username) @@ -101,9 +61,11 @@ def keys_for(username) username: username ).keys rescue Github::Auth::KeysClient::GithubUserDoesNotExistError - print_github_user_does_not_exist username + puts "Github user '#{username}' does not exist" rescue Github::Auth::KeysClient::GithubUnavailableError - print_github_unavailable + puts "Github appears to be unavailable :(" + puts + puts "https://status.github.com" end def keys_file diff --git a/lib/github/auth/options.rb b/lib/github/auth/options.rb new file mode 100644 index 0000000..e90332e --- /dev/null +++ b/lib/github/auth/options.rb @@ -0,0 +1,64 @@ +require 'optparse' + +module Github::Auth + # Parses command line options + class Options + attr_reader :parser + + def initialize + @parser = OptionParser.new do |opts| + opts.banner = [ + 'usage: gh-auth', + '[--version]', + '[--list]', + '[--add|--remove]', + '' + ].join(' ') + + opts.separator "\noptions:" + + opts.on( + '--add doug,sally', Array, 'Add GitHub users' + ) do |usernames| + raise OptionParser::MissingArgument if usernames.empty? + @command = 'add' + @usernames = usernames + end + + opts.on( + '--remove doug,sally', Array, 'Remove GitHub users' + ) do |usernames| + raise OptionParser::MissingArgument if usernames.empty? + @command = 'remove' + @usernames = usernames + end + + opts.on('--list', 'List all GitHub users added') do + @command = 'list' + end + + opts.on('--version', 'Show version') do + @command = 'version' + end + end + end + + def command + @command ||= 'usage' + end + + def usernames + @usernames ||= [] + end + + def usage + parser.help + end + + def parse(args) + parser.parse(args) + ensure + return self + end + end +end diff --git a/spec/acceptance/github/auth/cli_spec.rb b/spec/acceptance/github/auth/cli_spec.rb index 015a41c..6a01b6d 100644 --- a/spec/acceptance/github/auth/cli_spec.rb +++ b/spec/acceptance/github/auth/cli_spec.rb @@ -11,8 +11,8 @@ after { keys_file.unlink } - def cli(argv) - described_class.new(argv).tap do |cli| + def cli + described_class.new.tap do |cli| cli.stub( github_hostname: hostname, keys_file_path: keys_file.path @@ -21,13 +21,13 @@ def cli(argv) end it 'adds and removes keys from the keys file' do - cli(%w(add chrishunt)).execute + cli.execute %w(--add chrishunt) keys_file.read.tap do |keys_file_content| keys.each { |key| expect(keys_file_content).to include key.to_s } end - cli(%w(remove chrishunt)).execute + cli.execute %w(--remove chrishunt) expect(keys_file.read).to be_empty @@ -35,10 +35,10 @@ def cli(argv) end it 'lists users from the keys file' do - cli(%w(add chrishunt)).execute + cli.execute %w(--add chrishunt) output = capture_stdout do - cli(%w(list)).execute + cli.execute %w(--list) end expect(output).to include('chrishunt') @@ -46,10 +46,18 @@ def cli(argv) it 'prints version information' do output = capture_stdout do - cli(%w(--version)).execute + cli.execute %w(--version) end expect(output).to include Github::Auth::VERSION end + + it 'prints usage for invalid arguments' do + [[], %w(invalid), %w(--add)].each do |invalid_arguments| + expect( + capture_stdout { cli.execute invalid_arguments } + ).to include 'usage: gh-auth' + end + end end end diff --git a/spec/unit/github/auth/cli_spec.rb b/spec/unit/github/auth/cli_spec.rb deleted file mode 100644 index c274c82..0000000 --- a/spec/unit/github/auth/cli_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'spec_helper' -require 'github/auth/cli' - -describe Github::Auth::CLI do - let(:argv) { [] } - - subject { described_class.new argv } - - describe '#execute' do - shared_examples_for 'a method that prints usage' do - it 'prints the usage' do - subject.should_receive(:print_usage) - subject.execute - end - end - - context 'when missing a command' do - let(:argv) { [] } - it_should_behave_like 'a method that prints usage' - end - - context 'with an invalid command' do - let(:argv) { ['invalid'] } - it_should_behave_like 'a method that prints usage' - end - - context 'when no usernames are provide' do - let(:argv) { ['add'] } - it_should_behave_like 'a method that prints usage' - end - - context 'with a valid action and usernames' do - let(:action) { 'add' } - let(:argv) { [action, 'chrishunt'] } - - it 'calls the method matching the action name' do - subject.should_receive(action) - subject.execute - end - end - end -end