github_cli 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -4,6 +4,11 @@ branches:
4
4
  only: master
5
5
  notifications:
6
6
  email:false
7
+ matrix:
8
+ allow_failures:
9
+ - rvm: ruby-head
10
+ - jruby
11
+ - rbx-19mode
7
12
  rvm:
8
13
  - 1.9.2
9
14
  - 1.9.3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ 0.4.2 (July 12, 2012)
2
+
3
+ * Add 'did you mean' help for mistyped commands.
4
+ * Add utility function for finding common prefix.
5
+ * Extract command usage and completion classes.
6
+ * Fix bug with all commands listing.
7
+ * Add arguments parser for required and optional arguments.
8
+ * Add non-required argument parsing to repository creation.
9
+ * Add new error type for required arguments.
10
+ * Fix bug with creating authorizations.
11
+
1
12
  0.4.1 (June 28, 2012)
2
13
 
3
14
  * Add search api commands.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- github_cli (0.4.1)
4
+ github_cli (0.4.2)
5
5
  github_api (~> 0.6)
6
6
  thor
7
7
 
data/README.md CHANGED
@@ -41,6 +41,28 @@ This will setup a `.githubrc` configuration file in your home directory with
41
41
  all the global settings. During the install process you will be prompted for your
42
42
  `authentication token`.
43
43
 
44
+ ### Arguments
45
+
46
+ The required arguments come first as per command description, then follow the optional arguments inside a `params` flag.
47
+
48
+ You can create repository by supplying parameters in the following way:
49
+
50
+ ```shell
51
+ ghc repo create octokit --params=description:'Test repo for kitty.'
52
+ ```
53
+
54
+ To create repository inside organization:
55
+
56
+ ```shell
57
+ ghc repo create github/octokit --params=description:'Test repo for kitty.'
58
+ ```
59
+
60
+ To find out which options are required and optional type:
61
+
62
+ ```shell
63
+ ghc repo help create
64
+ ```
65
+
44
66
  ### Getting a list of commands
45
67
 
46
68
  You can list all GitHub APIs comamnds:
@@ -55,6 +77,38 @@ to limit returned results pass `pattern`
55
77
  $ ghc list re* # Returns all commands matching the pattern
56
78
  ```
57
79
 
80
+ ### Output Format
81
+
82
+ The API responses can be formatted as `csv`, `json`, `pretty`, `table`.
83
+
84
+ By default responses are in tabular format. Tables are available in `horizontal` and `vertical` mode. To enforce table display pass `:h` and `:v` respectively. Otherwise a default orientation will be picked depending on the request made and terminal size.
85
+
86
+ ```shell
87
+ ghc user get -u peter-murach --format=table:h
88
+
89
+ ┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳
90
+ ┃ type ┃ login ┃ public_… ┃ blog ┃ hireable ┃ followe… ┃ followi… ┃ location ┃ html_url ┃ name ┃
91
+ ┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋
92
+ ┃ User ┃ peter-m… ┃ 14 ┃ peter-m… ┃ false ┃ 18 ┃ 52 ┃ Sheffie… ┃ https:/… ┃ Piotr M… ┃
93
+ ┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻
94
+ ```
95
+
96
+ To get `csv` formatting for easy command piping do
97
+
98
+ ```shell
99
+ ghc repo ls -u wycats --format=csv
100
+ ```
101
+
102
+ ### Output Paging
103
+
104
+ By default all responses are paged. You can switch off paging by supplying `no-pager` flag.
105
+
106
+ ```shell
107
+ ghc --no-pager user ls -u wycats
108
+ ```
109
+
110
+ Also you can supply you preferred `pager`, otherwise the paging program is taken from environment variable PAGER if defined or defaults to "less".
111
+
58
112
  ### API
59
113
 
60
114
  Interact with git data:
@@ -73,6 +127,7 @@ Interact with issues:
73
127
  $ ghc issue
74
128
  $ ghc label
75
129
  $ ghc milestone
130
+ $ ghc comment
76
131
  ```
77
132
 
78
133
  Interact with repositories:
@@ -80,6 +135,7 @@ Interact with repositories:
80
135
  ```shell
81
136
  $ ghc repo
82
137
  $ ghc collab
138
+ $ ghc content
83
139
  $ ghc download
84
140
  $ ghc fork
85
141
  $ ghc hook
@@ -121,52 +177,6 @@ Interact with search:
121
177
  $ ghc search
122
178
  ```
123
179
 
124
- ### Output Format
125
-
126
- The API responses can be formatted as `csv`, `json`, `pretty`, `table`.
127
-
128
- By default responses are in tabular format. Tables are available in `horizontal` and `vertical` mode. To enforce table display pass `:h` and `:v` respectively. Otherwise a default orientation will be picked depending on the request made and terminal size.
129
-
130
- ```shell
131
- ghc user get -u peter-murach --format=table:h
132
-
133
- ┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳
134
- ┃ type ┃ login ┃ public_… ┃ blog ┃ hireable ┃ followe… ┃ followi… ┃ location ┃ html_url ┃ name ┃
135
- ┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋
136
- ┃ User ┃ peter-m… ┃ 14 ┃ peter-m… ┃ false ┃ 18 ┃ 52 ┃ Sheffie… ┃ https:/… ┃ Piotr M… ┃
137
- ┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻
138
- ```
139
-
140
- To get `csv` formatting for easy command piping do
141
-
142
- ```shell
143
- ghc repo ls -u wycats --format=csv
144
- ```
145
-
146
- ### Output Paging
147
-
148
- By default all responses are paged. You can switch off paging by supplying `no-pager` flag.
149
-
150
- ```shell
151
- ghc --no-pager user ls -u wycats
152
- ```
153
-
154
- Also you can supply you preferred `pager`, otherwise the paging program is taken from environment variable PAGER if defined or defaults to "less".
155
-
156
- ### Examples
157
-
158
- You can create repository by supplying required parameters
159
-
160
- ```shell
161
- ghc repo create --params=name:'octocat' description:'Test repo for kitty.'
162
- ```
163
-
164
- To find out which options are required type
165
-
166
- ```shell
167
- ghc repo help create
168
- ```
169
-
170
180
  ## Contributing
171
181
 
172
182
  1. Fork it
@@ -0,0 +1,32 @@
1
+ Feature: Command Completion
2
+
3
+ Scenario: Suggest alternative
4
+
5
+ When I run `ghc blah`
6
+ Then the exit status should be 0
7
+ And the output should contain:
8
+ """
9
+ Did you mean this?
10
+ blob
11
+ """
12
+
13
+ Scenario: Suggest more than one
14
+
15
+ When I run `ghc convent`
16
+ Then the exit status should be 0
17
+ And the output should contain:
18
+ """
19
+ Did you mean this?
20
+ collab
21
+ commit
22
+ content
23
+ """
24
+
25
+ Scenario: Suggset nothing
26
+
27
+ When I run `ghc xen`
28
+ Then the exit status should be 0
29
+ And the output should not contain:
30
+ """
31
+ Did you mean this?
32
+ """
@@ -18,17 +18,6 @@ Feature: The GHC Executable
18
18
  | |
19
19
  | help |
20
20
 
21
- Scenario: Getting Usage for Commands
22
-
23
- When I run `ghc`
24
- Then the exit status should be 0
25
- And the output should contain "Usage: ghc"
26
- And the output should contain "[--config]"
27
- And the output should contain "[--no-color]"
28
- And the output should contain "[--no-pager]"
29
- And the output should contain "[--version]"
30
- And the output should contain "[--verbose]"
31
-
32
21
  Scenario Outline: Getting Subcommands
33
22
 
34
23
  When I run `ghc <command>`
@@ -1,6 +1,7 @@
1
1
  require 'fileutils'
2
2
 
3
3
  Before do
4
+ @aruba_timeout_seconds = 5
4
5
  @real_home = ENV['HOME']
5
6
  fake_home = File.join('/tmp', 'fakehome')
6
7
  FileUtils.rm_rf fake_home if File.exists? fake_home
@@ -0,0 +1,18 @@
1
+ Feature: Command Usage
2
+
3
+ Scenario: Getting Usage for Commands
4
+
5
+ When I run `ghc`
6
+ Then the exit status should be 0
7
+ And the output should contain "Usage: ghc"
8
+ And the output should contain "[--config]"
9
+ And the output should contain "[--no-color]"
10
+ And the output should contain "[--no-pager]"
11
+ And the output should contain "[--version]"
12
+ And the output should contain "[--verbose]"
13
+
14
+ Scenario: Specific usage for command
15
+
16
+ When I run `ghc repo`
17
+ Then the exit status should be 0
18
+ And the output should contain "repo <subcommand>"
data/github_cli.gemspec CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../lib/github_cli/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Piotr Murach"]
6
- gem.email = ["pmurach@gmail.com"]
6
+ gem.email = [""]
7
7
  gem.description = %q{CLI-based access to GitHub API v3}
8
8
  gem.summary = %q{github_cli is a set of tools that provide full command line access to GitHub API v3}
9
9
  gem.homepage = "http://github.com/peter-murach/github_cli"
@@ -4,10 +4,14 @@ module GithubCLI
4
4
  # The API class is the main entry point for creating GithubCLI APIs.
5
5
  class API
6
6
 
7
+ ENDPOINT = ''
8
+
7
9
  @@api = nil
8
10
 
9
11
  class << self
10
12
 
13
+ attr_reader :config
14
+
11
15
  def github_api
12
16
  @@api ||= begin
13
17
  @@api = configure_api
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ module GithubCLI
4
+ class Command
5
+ # Makes it easy to parse required and options arguments.
6
+ class Arguments
7
+
8
+ SEPARATOR = '/'
9
+
10
+ attr_reader :args
11
+
12
+ def initialize(args)
13
+ @args = args
14
+ end
15
+
16
+ # Returns seperated arguments
17
+ def parse
18
+ required, non_required = nil, nil
19
+
20
+ if !args.empty?
21
+ required = args
22
+ non_required, required = required.split('/', 2) if required.index('/')
23
+ else
24
+ raise RequiredArgumentMissingError, "No value provided for required argument"
25
+ end
26
+ [non_required, required]
27
+ end
28
+
29
+ # Returns a concise string representation of Arguments instance
30
+ #
31
+ def inspect
32
+ "#<#{self.class.inspect} @args=#{args.inspect}"
33
+ end
34
+
35
+ end # Arguments
36
+ end # Command
37
+ end # GithubCLI
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+
3
+ module GithubCLI
4
+ # Provides command completion/suggestion for mistyped command or subcommand.
5
+ class Command
6
+ class Completion
7
+ include GithubCLI::Util
8
+
9
+ # Command to be looked up.
10
+ attr_accessor :command
11
+
12
+ def initialize(command)
13
+ @command = command
14
+ end
15
+
16
+ DEFAULT_INDENT = 8
17
+
18
+ # If there is more than one possible alternative, show all of them.
19
+ #
20
+ def find_command_possibilities
21
+ max_length = 1
22
+ commands = Command.all.select do |cmd|
23
+ prefix = Util.longest_common_prefix(command, cmd.namespace)
24
+ if !prefix.empty? && (prefix.length >= max_length)
25
+ max_length = prefix.length
26
+ cmd
27
+ end
28
+ end
29
+ commands.map(&:namespace).uniq.sort
30
+ end
31
+
32
+ # Options
33
+ # indent - Indent suggested commands by specified value.
34
+ #
35
+ def format_command_possibilities(options={})
36
+ possibilities = find_command_possibilities
37
+ string = ""
38
+ indent = options[:indent] || DEFAULT_INDENT
39
+ if possibilities.size >= 1
40
+ string << "\n\nDid you mean this?\n"
41
+ possibilities.each do |possibility|
42
+ string << " " * indent + "#{possibility}\n"
43
+ end
44
+ end
45
+ string
46
+ end
47
+
48
+ # Returns a concise string representation of Completion instance
49
+ #
50
+ def inspect
51
+ "#<#{self.class.inspect} @command=#{command.inspect}"
52
+ end
53
+
54
+ end # Completion
55
+ end # Command
56
+ end # GithubCLI
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ module GithubCLI
4
+ # Responsible for manipulating commands usage string.
5
+ class Command
6
+ class Usage
7
+
8
+ DEFAULT_INDENT = 11
9
+
10
+ # Returns command
11
+ attr_reader :command
12
+
13
+ # Returns command flags
14
+ attr_reader :flags
15
+
16
+ # Initializes an usage instance
17
+ #
18
+ def initialize(command, flags, options={})
19
+ @command = Command.command_to_show(command)
20
+ @flags = flags
21
+ end
22
+
23
+ # Options
24
+ # indent - Indent the line with by indent value. Assumes that the first
25
+ # the first line is already filled in with other padding.
26
+ # length - Line length, otherwise the default terminal width is assumed.
27
+ def format_usage(options={})
28
+ synopsis = "#{flags} #{command} <subcommand> [<args>]"
29
+ indent = options[:indent] || DEFAULT_INDENT
30
+ padding = sprintf("%#{indent}s",'')
31
+ length = options[:length] || Terminal.default_width
32
+ wrap synopsis, length, indent, padding
33
+ end
34
+
35
+ def tokenize_text(text)
36
+ text.split(/\s+/).map(&:chomp).reject(&:empty?)
37
+ end
38
+
39
+ # Wraps text at the given line length using given indent value.
40
+ #
41
+ def wrap(text, length, indent=0, padding=0)
42
+ if text.length > length - indent
43
+ paragraphs = []
44
+ line = ''
45
+ tokenize_text(text).each do |fragment|
46
+ if line.length < length - indent
47
+ line << fragment + ' '
48
+ else
49
+ paragraphs << line
50
+ line = padding + fragment + ' '
51
+ end
52
+ end
53
+ paragraphs << line
54
+ text = paragraphs.join("\n")
55
+ end
56
+ text
57
+ end
58
+
59
+ # Returns a concise string representation of Usage instance
60
+ #
61
+ def inspect
62
+ "#<#{self.class.inspect} @command=#{command.inspect} @flags=#{flags.inspect}"
63
+ end
64
+
65
+ end # Usage
66
+ end # Command
67
+ end # GithubCLI
@@ -29,9 +29,15 @@ module GithubCLI
29
29
  }
30
30
  end
31
31
 
32
- map "ls" => :list,
33
- "all" => :list,
34
- "del" => :delete
32
+ ALIASES = {
33
+ "ls" => :list,
34
+ "all" => :list,
35
+ "del" => :delete,
36
+ "rm" => :delete,
37
+ "c" => :create,
38
+ "e" => :edit
39
+ }
40
+ map ALIASES
35
41
 
36
42
  class_option :params, :type => :hash, :default => {}, :aliases => '-p',
37
43
  :desc => 'Request parameters e.i per_page:100'
@@ -74,6 +80,8 @@ module GithubCLI
74
80
  klass.namespace.split(':').last
75
81
  end
76
82
 
83
+ # Decide whether to show specific command or placeholder
84
+ #
77
85
  def command_to_show(command)
78
86
  command_token = Command.all.find do |cmd|
79
87
  end_index = command.index('<').nil? ? -1 : command.index('<')
@@ -6,29 +6,31 @@ module GithubCLI
6
6
  namespace :auth
7
7
 
8
8
  desc 'list', 'Lists your authorizations'
9
- method_option :params, :type => :hash, :default => {},
10
- :desc => 'Additional request parameters e.i per_page:100'
9
+ long_desc <<-DESC
10
+ You can only list your own tokens, and only through Basic Authentication.
11
+ DESC
11
12
  def list
12
13
  Authorization.all options[:params], options[:formats]
13
14
  end
14
15
 
15
16
  desc 'get <id>', 'Get a single authorization'
16
- method_option :params, :type => :hash, :default => {},
17
- :desc => 'Additional request parameters e.i per_page:100'
17
+ long_desc <<-DESC
18
+ You can only access your own token, and only through Basic Authentication.
19
+ DESC
18
20
  def get(id)
19
21
  Authorization.get id, options[:params], options[:format]
20
22
  end
21
23
 
22
- desc 'create <user> <repo>', 'Create a new authorization'
24
+ desc 'create', 'Create a new authorization'
23
25
  long_desc <<-DESC
26
+ You can only create your own token, and only through Basic Authentication.\n
27
+
24
28
  Inputs
25
29
 
26
30
  scopes - Optional array - A list of scopes that this authorization is in.\n
27
31
  note - Optional string - A note to remind you what the OAuth token is for.\n
28
32
  note_url - Optional string - A URL to remind you what the OAuth token is for.
29
33
  DESC
30
- method_option :params, :type => :hash, :default => {},
31
- :desc => 'Additonal request parameters e.i per_page:100'
32
34
  def create
33
35
  Authorization.create options[:params], options[:format]
34
36
  end
@@ -48,8 +50,6 @@ module GithubCLI
48
50
  end
49
51
 
50
52
  desc 'delete <id>', 'Delete an authorization'
51
- method_option :params, :type => :hash, :default => {},
52
- :desc => 'Additonal request parameters e.i per_page:100'
53
53
  def delete(id)
54
54
  Authorization.delete id, options[:params], options[:format]
55
55
  end
@@ -10,7 +10,7 @@ module GithubCLI
10
10
  Email.all options[:params], options[:format]
11
11
  end
12
12
 
13
- desc 'add <email(s)>', 'Add email address(es) for the authenticated user'
13
+ desc 'add <email(s)>...', 'Add email address(es) for the authenticated user'
14
14
  long_desc <<-DESC
15
15
  You can include a single email address or an array of addresses
16
16
  DESC
@@ -18,7 +18,7 @@ module GithubCLI
18
18
  Email.add emails, options[:params], options[:format]
19
19
  end
20
20
 
21
- desc 'delete <email(s)>', 'Delete email address(es) for the authenticated user'
21
+ desc 'delete <email(s)>...', 'Delete email address(es) for the authenticated user'
22
22
  long_desc <<-DESC
23
23
  You can include a single email address or an array of addresses
24
24
  DESC
@@ -4,8 +4,9 @@ module GithubCLI
4
4
  class Commands::Repositories < Command
5
5
 
6
6
  namespace :repo
7
+ # TODO: format_type options[:format]
7
8
 
8
- desc 'list', 'Lists all repositories'
9
+ desc 'list', 'Lists all repositories for the authenticated user'
9
10
  method_option :org, :type => :string, :aliases => ["-o"],
10
11
  :desc => 'List repositories for <organization>',
11
12
  :banner => '<organization>'
@@ -26,13 +27,12 @@ module GithubCLI
26
27
  Repository.get user, repo, options[:params], options[:format]
27
28
  end
28
29
 
29
- desc 'create', 'Create a new repository for the authenticated user.'
30
+ desc 'create [<org>/]<name>', 'Create a new repository <name> for the authenticated user.'
30
31
  long_desc <<-DESC
31
32
  Create a new repository for the autheticated user.
32
33
 
33
34
  Parameters
34
35
 
35
- name - Required string \n
36
36
  description - Optional string \n
37
37
  homepage - Optional string \n
38
38
  private - Optional boolean - true to create a private repository, false to create a public one \n
@@ -45,10 +45,11 @@ module GithubCLI
45
45
  method_option :org, :type => :string, :aliases => ["-o"],
46
46
  :desc => 'Create repository in <organization>',
47
47
  :banner => '<organization>'
48
- def create
49
- if options[:org]
50
- options[:params]['org'] = options[:org]
51
- end
48
+ def create(args)
49
+ org, options[:params]['name'] = Arguments.new(args).parse
50
+ options[:params]['org'] = org if org
51
+ options[:params]['org'] = options[:org] if options[:org]
52
+
52
53
  Repository.create options[:params], options[:format]
53
54
  end
54
55
 
@@ -2,10 +2,13 @@
2
2
 
3
3
  module GithubCLI
4
4
  class Config
5
- COMMAND_KEY = 'commands'
5
+
6
+ COMMAND_KEY = 'commands'
6
7
  COMMAND_HELP = 'help'
7
8
 
8
- def initialize(root)
9
+ attr_reader :root
10
+
11
+ def initialize(root, options={})
9
12
  @root = root
10
13
  @local_config = local_options_file
11
14
  @global_config = global_options_file
@@ -69,7 +72,7 @@ module GithubCLI
69
72
  private
70
73
 
71
74
  def local_options_file
72
- Pathname.new "#{@root}/.githubrc"
75
+ Pathname.new "#{root}/.githubrc"
73
76
  end
74
77
 
75
78
  def global_options_file
@@ -90,5 +93,9 @@ module GithubCLI
90
93
  value
91
94
  end
92
95
 
96
+ def inspect
97
+ "#{self.class.inspect} @root=#{root}"
98
+ end
99
+
93
100
  end # Config
94
101
  end # GithubCLI
@@ -17,5 +17,12 @@ module GithubCLI
17
17
  def on_error(&block)
18
18
  @@error_block = block
19
19
  end
20
+
21
+ def before(&block)
22
+ end
23
+
24
+ def configure(&block)
25
+ end
26
+
20
27
  end
21
28
  end
@@ -12,6 +12,10 @@ module GithubCLI
12
12
  status_code 5
13
13
  end
14
14
 
15
+ class RequiredArgumentMissingError < GithubCLIError
16
+ status_code 6
17
+ end
18
+
15
19
  # Raised when a configuration file is corrupt or missing.
16
20
  class ConfigFileNotFound < GithubCLIError
17
21
  status_code 10
@@ -3,6 +3,7 @@
3
3
  module GithubCLI
4
4
  # Responsible for display and size detection.
5
5
  class Terminal
6
+
6
7
  DEFAULT_WIDTH = 80
7
8
  DEFAULT_HEIGHT = 40
8
9
 
@@ -38,25 +39,13 @@ module GithubCLI
38
39
  @pager ||= Pager.new
39
40
  end
40
41
 
41
- def print_commands(pattern=nil)
42
- Terminal.line "\n" + GithubCLI.program_name + "\n"
43
- Terminal.newline
44
- GithubCLI.ui.info "Commands:"
45
-
46
- commands = Command.all.select do |cmd|
42
+ def find_commands(pattern=nil)
43
+ Command.all.select do |cmd|
47
44
  cmd if pattern && cmd.namespace =~ pattern
48
- end.map do |cmd|
49
- build_command cmd
50
- end
51
-
52
- if !commands.empty?
53
- GithubCLI.ui.print_table commands, :truncate => true
54
- else
55
- print_command_not_found pattern.to_s.gsub(/\W|/, '')[3..-1]
56
45
  end
57
46
  end
58
47
 
59
- def build_command(cmd, indent=3)
48
+ def build_command_output(cmd, indent=3)
60
49
  prefix = " " * indent
61
50
  if cmd.namespace.empty?
62
51
  ["#{prefix + cmd.usage}", cmd.desc]
@@ -65,6 +54,19 @@ module GithubCLI
65
54
  end
66
55
  end
67
56
 
57
+ def print_commands(pattern=nil)
58
+ Terminal.line "\n" + GithubCLI.program_name + "\n\n"
59
+
60
+ commands = find_commands(pattern).map { |cmd| build_command_output cmd }
61
+
62
+ if !commands.empty?
63
+ GithubCLI.ui.info "Commands:"
64
+ GithubCLI.ui.print_table commands, :truncate => true
65
+ else
66
+ print_command_not_found pattern.to_s.gsub(/\W|/, '')[3..-1]
67
+ end
68
+ end
69
+
68
70
  def print_command_not_found(cmd)
69
71
  GithubCLI.ui.info "ghc: '#{cmd}' is not a ghc command. See 'ghc --help'."
70
72
  end
@@ -74,42 +76,11 @@ module GithubCLI
74
76
 
75
77
  #{GithubCLI.program_name}
76
78
 
77
- Usage: ghc #{format_usage(flags, command, :indent => 11)}
79
+ Usage: ghc #{GithubCLI::Command::Usage.new(command, flags).format_usage }
78
80
 
79
81
  TEXT
80
82
  end
81
83
 
82
- # Options
83
- # indent - Indent the line with by indent value. Assumes that the first
84
- # the first line is already filled in with other padding.
85
- # length - Line length, otherwise the default terminal width is assumed.
86
- def format_usage(flags, command, options={})
87
- synopsis = "#{flags} #{command} <subcommand> [<args>]"
88
- indent = options[:indent] || 0
89
- padding = sprintf("%#{indent}s",'')
90
- length = options[:length] || default_width
91
- wrap synopsis, length, indent, padding
92
- end
93
-
94
- # Wraps text at the given line length using given indent value.
95
- def wrap(text, length, indent=0, padding=0)
96
- if text.length > length - indent
97
- paragraphs = []
98
- line = ''
99
- text.split(/\s+/).map(&:chomp).reject(&:empty?).each do |fragment|
100
- if line.length < length - indent
101
- line << fragment + ' '
102
- else
103
- paragraphs << line
104
- line = padding + fragment + ' '
105
- end
106
- end
107
- paragraphs << line
108
- text = paragraphs.join("\n")
109
- end
110
- text
111
- end
112
-
113
84
  end
114
85
 
115
86
  end # Terminal
@@ -1,3 +1,4 @@
1
+ require 'github_cli'
1
2
  require 'thor'
2
3
 
3
4
  class Thor
@@ -12,7 +13,7 @@ class Thor
12
13
  end
13
14
  list.sort!{ |a,b| a[0] <=> b[0] }
14
15
 
15
- GithubCLI::Terminal.print_usage global_flags, GithubCLI::Command.command_to_show(list[0][0])
16
+ GithubCLI::Terminal.print_usage global_flags, list[0][0]
16
17
 
17
18
  shell.say "Commands:"
18
19
  shell.print_table(list, :indent => 2, :truncate => true)
@@ -39,6 +40,15 @@ class Thor
39
40
  def help(task = nil, subcommand = true); super; end
40
41
  RUBY
41
42
  end
43
+
44
+ def handle_no_task_error(cmd, has_namespace = $thor_runner) #:nodoc:
45
+ possibilities = "#{GithubCLI::Command::Completion.new(cmd).format_command_possibilities}"
46
+ if has_namespace
47
+ raise UndefinedTaskError, "Could not find task #{cmd.inspect} in #{namespace.inspect} namespace. " + possibilities
48
+ else
49
+ raise UndefinedTaskError, "Could not find command #{cmd.inspect}. " + possibilities
50
+ end
51
+ end
42
52
  end
43
53
 
44
54
  desc "help <command>", "Describe available commands or one specific command"
@@ -4,6 +4,8 @@ module GithubCLI
4
4
  module Util
5
5
  extend self
6
6
 
7
+ # Converts deeply nested hash into only one level structure
8
+ #
7
9
  def flatten_hash(prefix=nil, hash)
8
10
  new_hash ||= {}
9
11
  hash.each do |key, val|
@@ -26,6 +28,8 @@ module GithubCLI
26
28
  end
27
29
  end
28
30
 
31
+ # Attempts to convert value object to string
32
+ #
29
33
  def convert_value(value)
30
34
  case value
31
35
  when true then "true"
@@ -38,6 +42,7 @@ module GithubCLI
38
42
 
39
43
  # Shortens string
40
44
  # :trailing - trailing character in place of cutout string
45
+ #
41
46
  def truncate(string, width, options={})
42
47
  trailing = options[:trailing] || '…'
43
48
 
@@ -52,6 +57,7 @@ module GithubCLI
52
57
  # Pads a string
53
58
  # padder - padding character
54
59
  # align - align :left, :right, :center
60
+ #
55
61
  def pad(string, width, options={})
56
62
  supported = [:left, :right, :center]
57
63
  padder = options[:padder] || ' '
@@ -74,5 +80,11 @@ module GithubCLI
74
80
  end
75
81
  string
76
82
  end
83
+
84
+ # Compares two strings to find common prefix
85
+ #
86
+ def longest_common_prefix(string_1, string_2)
87
+ ("#{string_1}\0#{string_2}").match(/^(.*).*\0\1/i).to_a[1]
88
+ end
77
89
  end
78
90
  end # GithubCLI
@@ -1,3 +1,3 @@
1
1
  module GithubCLI
2
- VERSION = "0.4.1"
2
+ VERSION = "0.4.2"
3
3
  end
data/lib/github_cli.rb CHANGED
@@ -9,6 +9,7 @@ require 'github_cli/thor_ext'
9
9
  require 'github_cli/version'
10
10
  require 'github_cli/errors'
11
11
 
12
+ # Base module which adds Github API to the command line
12
13
  module GithubCLI
13
14
  autoload :DSL, 'github_cli/dsl'
14
15
  autoload :Config, 'github_cli/config'
@@ -26,10 +27,13 @@ module GithubCLI
26
27
  autoload :Util, 'github_cli/util'
27
28
 
28
29
  require 'github_cli/apis'
30
+ require 'github_cli/command/completion'
31
+ require 'github_cli/command/usage'
32
+ require 'github_cli/command/arguments'
29
33
 
30
34
  extend DSL
31
35
 
32
- program_name 'Github CLI client'
36
+ program_name 'GitHub API v3 CLI client'
33
37
 
34
38
  class << self
35
39
  attr_writer :ui, :config
@@ -3,13 +3,8 @@ require 'spec_helper'
3
3
  describe GithubCLI::Pager do
4
4
 
5
5
  context '#pager_command' do
6
- it 'chooses default pagers if none present' do
7
- GithubCLI::System.stub(:command?) { true }
8
- described_class.pager_command.to_s.should =~ /less/
9
- end
10
-
11
6
  it 'permits custom commands' do
12
- cmd = 'mine'
7
+ cmd = 'more'
13
8
  GithubCLI::System.stub(:command?) { true }
14
9
  described_class.pager_command(cmd).should == cmd
15
10
  end
@@ -44,4 +44,16 @@ describe GithubCLI::Util do
44
44
  subject.convert_value(values).should eq(["123", "baz", "2.3"])
45
45
  end
46
46
  end
47
+
48
+ describe '#longest_common_prefix' do
49
+ it 'finds common prefix' do
50
+ a = 'tribe'; b = 'tree'
51
+ subject.longest_common_prefix(a,b).should == "tr"
52
+ end
53
+
54
+ it 'fails to find common prefix' do
55
+ a = 'foo'; b = 'bar'
56
+ subject.longest_common_prefix(a,b).should be_empty
57
+ end
58
+ end
47
59
  end # GithubCLI::Util
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: github_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-28 00:00:00.000000000Z
12
+ date: 2012-07-12 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: github_api
16
- requirement: &2156342420 !ruby/object:Gem::Requirement
16
+ requirement: &2153403460 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0.6'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2156342420
24
+ version_requirements: *2153403460
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: thor
27
- requirement: &2156342000 !ruby/object:Gem::Requirement
27
+ requirement: &2153403000 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2156342000
35
+ version_requirements: *2153403000
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &2156341520 !ruby/object:Gem::Requirement
38
+ requirement: &2153402520 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2156341520
46
+ version_requirements: *2153402520
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: aruba
49
- requirement: &2156341020 !ruby/object:Gem::Requirement
49
+ requirement: &2153401860 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2156341020
57
+ version_requirements: *2153401860
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &2156340580 !ruby/object:Gem::Requirement
60
+ requirement: &2153401360 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *2156340580
68
+ version_requirements: *2153401360
69
69
  description: CLI-based access to GitHub API v3
70
70
  email:
71
- - pmurach@gmail.com
71
+ - ''
72
72
  executables:
73
73
  - ghc
74
74
  extensions: []
@@ -88,6 +88,7 @@ files:
88
88
  - features/blob.feature
89
89
  - features/collaborator.feature
90
90
  - features/commit.feature
91
+ - features/completion.feature
91
92
  - features/content.feature
92
93
  - features/download.feature
93
94
  - features/email.feature
@@ -113,9 +114,9 @@ files:
113
114
  - features/tag.feature
114
115
  - features/team.feature
115
116
  - features/tree.feature
117
+ - features/usage.feature
116
118
  - features/user.feature
117
119
  - features/watching.feature
118
- - fixtures/.githubrc
119
120
  - fixtures/simple_config
120
121
  - ghc_logo.png
121
122
  - github_cli.gemspec
@@ -151,6 +152,9 @@ files:
151
152
  - lib/github_cli/apis/watching.rb
152
153
  - lib/github_cli/cli.rb
153
154
  - lib/github_cli/command.rb
155
+ - lib/github_cli/command/arguments.rb
156
+ - lib/github_cli/command/completion.rb
157
+ - lib/github_cli/command/usage.rb
154
158
  - lib/github_cli/commands.rb
155
159
  - lib/github_cli/commands/authorizations.rb
156
160
  - lib/github_cli/commands/blobs.rb
@@ -233,6 +237,7 @@ test_files:
233
237
  - features/blob.feature
234
238
  - features/collaborator.feature
235
239
  - features/commit.feature
240
+ - features/completion.feature
236
241
  - features/content.feature
237
242
  - features/download.feature
238
243
  - features/email.feature
@@ -258,6 +263,7 @@ test_files:
258
263
  - features/tag.feature
259
264
  - features/team.feature
260
265
  - features/tree.feature
266
+ - features/usage.feature
261
267
  - features/user.feature
262
268
  - features/watching.feature
263
269
  - spec/github_cli/api_spec.rb
data/fixtures/.githubrc DELETED
@@ -1,9 +0,0 @@
1
- ---
2
- oauth_token: ad7f9asdf97as98df7as9fd7
3
- basic_auth: 'login:password'
4
- host:
5
- user:
6
- repo:
7
- commands:
8
- issue-list: { inputs: 'ticket' }
9
- issue-get: {}