abt-cli 0.0.21 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/bin/abt +3 -3
  3. data/lib/abt.rb +6 -6
  4. data/lib/abt/ari.rb +1 -1
  5. data/lib/abt/ari_list.rb +1 -1
  6. data/lib/abt/base_command.rb +7 -7
  7. data/lib/abt/cli.rb +27 -40
  8. data/lib/abt/cli/arguments_parser.rb +5 -9
  9. data/lib/abt/cli/global_commands.rb +23 -0
  10. data/lib/abt/cli/global_commands/commands.rb +2 -2
  11. data/lib/abt/cli/global_commands/examples.rb +2 -2
  12. data/lib/abt/cli/global_commands/help.rb +2 -2
  13. data/lib/abt/cli/global_commands/readme.rb +2 -2
  14. data/lib/abt/cli/global_commands/share.rb +6 -6
  15. data/lib/abt/cli/global_commands/version.rb +2 -2
  16. data/lib/abt/cli/prompt.rb +51 -20
  17. data/lib/abt/docs.rb +39 -33
  18. data/lib/abt/docs/cli.rb +3 -3
  19. data/lib/abt/docs/markdown.rb +5 -5
  20. data/lib/abt/git_config.rb +4 -6
  21. data/lib/abt/providers/asana/api.rb +9 -9
  22. data/lib/abt/providers/asana/base_command.rb +8 -10
  23. data/lib/abt/providers/asana/commands/add.rb +13 -12
  24. data/lib/abt/providers/asana/commands/branch_name.rb +8 -8
  25. data/lib/abt/providers/asana/commands/clear.rb +7 -8
  26. data/lib/abt/providers/asana/commands/current.rb +14 -14
  27. data/lib/abt/providers/asana/commands/finalize.rb +11 -12
  28. data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +11 -11
  29. data/lib/abt/providers/asana/commands/init.rb +8 -41
  30. data/lib/abt/providers/asana/commands/pick.rb +17 -17
  31. data/lib/abt/providers/asana/commands/projects.rb +5 -5
  32. data/lib/abt/providers/asana/commands/share.rb +5 -5
  33. data/lib/abt/providers/asana/commands/start.rb +21 -20
  34. data/lib/abt/providers/asana/commands/tasks.rb +6 -6
  35. data/lib/abt/providers/asana/configuration.rb +25 -25
  36. data/lib/abt/providers/asana/path.rb +5 -5
  37. data/lib/abt/providers/devops/api.rb +12 -12
  38. data/lib/abt/providers/devops/base_command.rb +10 -10
  39. data/lib/abt/providers/devops/commands/boards.rb +5 -7
  40. data/lib/abt/providers/devops/commands/branch_name.rb +9 -9
  41. data/lib/abt/providers/devops/commands/clear.rb +7 -8
  42. data/lib/abt/providers/devops/commands/current.rb +17 -17
  43. data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +13 -13
  44. data/lib/abt/providers/devops/commands/init.rb +17 -13
  45. data/lib/abt/providers/devops/commands/pick.rb +11 -11
  46. data/lib/abt/providers/devops/commands/share.rb +5 -5
  47. data/lib/abt/providers/devops/commands/{work-items.rb → work_items.rb} +3 -3
  48. data/lib/abt/providers/devops/configuration.rb +19 -15
  49. data/lib/abt/providers/devops/path.rb +5 -4
  50. data/lib/abt/providers/git/commands/branch.rb +17 -19
  51. data/lib/abt/providers/harvest/api.rb +8 -8
  52. data/lib/abt/providers/harvest/base_command.rb +6 -8
  53. data/lib/abt/providers/harvest/commands/clear.rb +7 -8
  54. data/lib/abt/providers/harvest/commands/current.rb +13 -13
  55. data/lib/abt/providers/harvest/commands/init.rb +10 -38
  56. data/lib/abt/providers/harvest/commands/pick.rb +11 -11
  57. data/lib/abt/providers/harvest/commands/projects.rb +5 -5
  58. data/lib/abt/providers/harvest/commands/share.rb +5 -5
  59. data/lib/abt/providers/harvest/commands/start.rb +5 -3
  60. data/lib/abt/providers/harvest/commands/stop.rb +12 -12
  61. data/lib/abt/providers/harvest/commands/tasks.rb +7 -7
  62. data/lib/abt/providers/harvest/commands/track.rb +21 -20
  63. data/lib/abt/providers/harvest/configuration.rb +18 -18
  64. data/lib/abt/providers/harvest/path.rb +5 -5
  65. data/lib/abt/version.rb +1 -1
  66. metadata +6 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce59010855d53bf8b8731a680d7adcd21cef4eb93d421174aee893f27350cb1e
4
- data.tar.gz: 8ac30f3ada5fcc7c75f7a9a91110340d579fd79d8c6226dd4f92a24bdf070d88
3
+ metadata.gz: 6b8172eca54c77feb083acbc9895bf9f221b69efc1c0b8170d87f250b486286a
4
+ data.tar.gz: e07e6122c3b3c3bc1307769f5d52d01cb6db9126df0fe10bfb217b940a1eaf12
5
5
  SHA512:
6
- metadata.gz: 0cdbbd886589a06d20281e67a8376b3292cd61e432b7b672c968e2c5730a65707cc60d31d179acdcd7ad2a5eab9ebffe15866e08f5001b1922f291007146038b
7
- data.tar.gz: d0e568a9db4e57207f1cd8d72c789fea3c456f282c6cc1b4a46694767317a0b5c4055d90d53903779c20cd7ecf3c5a0803b07ebafb03b9e07d5ed99f3be14a88
6
+ metadata.gz: 5eee8193b985110d79170134593fa1ac03b50f6be36b43fa99bb99c8bdcf51d531f9e2b10fe5bca919524f388f503a3a46b9d74bf4764226e6f8d94b905d12ca
7
+ data.tar.gz: 3a3d7f288dbf3faaab041934bcf703afbaa87b989a1e869bae02a084c83834fd02a1a93df78ed06b2bb6a0b29f4167cdae8a972940c6684e9660dd58d06a78ba
data/bin/abt CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative '../lib/abt.rb'
4
+ require_relative "../lib/abt"
5
5
 
6
6
  begin
7
7
  Abt::Cli.new.perform
8
8
  rescue Abt::Cli::Abort => e
9
- abort e.message
9
+ abort(e.message)
10
10
  rescue Interrupt
11
- abort 'Aborted'
11
+ abort("Aborted")
12
12
  end
data/lib/abt.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry-inflector'
4
- require 'faraday'
5
- require 'oj'
6
- require 'open3'
7
- require 'stringio'
8
- require 'optparse'
3
+ require "dry-inflector"
4
+ require "faraday"
5
+ require "oj"
6
+ require "open3"
7
+ require "stringio"
8
+ require "optparse"
9
9
 
10
10
  Dir.glob("#{File.dirname(File.absolute_path(__FILE__))}/abt/*.rb").sort.each do |file|
11
11
  require file
data/lib/abt/ari.rb CHANGED
@@ -14,7 +14,7 @@ module Abt
14
14
  str = scheme
15
15
  str += ":#{path}" if path
16
16
 
17
- [str, *flags].join(' ')
17
+ [str, *flags].join(" ")
18
18
  end
19
19
  end
20
20
  end
data/lib/abt/ari_list.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Abt
4
4
  class AriList < Array
5
5
  def to_s
6
- map(&:to_s).join(' -- ')
6
+ map(&:to_s).join(" -- ")
7
7
  end
8
8
 
9
9
  def -(other)
@@ -5,11 +5,11 @@ module Abt
5
5
  extend Forwardable
6
6
 
7
7
  def self.usage
8
- raise NotImplementedError, 'Command classes must implement .usage'
8
+ raise NotImplementedError, "Command classes must implement .usage"
9
9
  end
10
10
 
11
11
  def self.description
12
- raise NotImplementedError, 'Command classes must implement .description'
12
+ raise NotImplementedError, "Command classes must implement .description"
13
13
  end
14
14
 
15
15
  def self.flags
@@ -27,7 +27,7 @@ module Abt
27
27
  end
28
28
 
29
29
  def perform
30
- raise NotImplementedError, 'Command classes must implement #perform'
30
+ raise NotImplementedError, "Command classes must implement #perform"
31
31
  end
32
32
 
33
33
  private
@@ -41,18 +41,18 @@ module Abt
41
41
 
42
42
  result
43
43
  rescue OptionParser::InvalidOption => e
44
- abort e.message
44
+ abort(e.message)
45
45
  end
46
46
 
47
47
  def flag_parser
48
48
  @flag_parser ||= OptionParser.new do |opts|
49
49
  opts.banner = <<~TXT
50
- #{self.class.description}
50
+ #{self.class.description.strip}
51
51
 
52
- Usage: #{self.class.usage}
52
+ Usage: #{self.class.usage.strip}
53
53
  TXT
54
54
 
55
- opts.on('-h', '--help', 'Display this help')
55
+ opts.on("-h", "--help", "Display this help")
56
56
 
57
57
  self.class.flags.each do |(*flag)|
58
58
  opts.on(*flag)
data/lib/abt/cli.rb CHANGED
@@ -1,31 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Dir.glob("#{File.expand_path(__dir__)}/cli/**/*.rb").sort.each do |file|
3
+ Dir.glob("#{File.expand_path(__dir__)}/cli/*.rb").sort.each do |file|
4
4
  require file
5
5
  end
6
6
 
7
7
  module Abt
8
8
  class Cli
9
9
  class Abort < StandardError; end
10
- class Exit < StandardError; end
11
-
12
- def self.global_command_names
13
- GlobalCommands.constants.sort.map { |constant_name| Helpers.const_to_command(constant_name) }
14
- end
15
-
16
- def self.global_command_class(name)
17
- name = 'help' if [nil, '-h', '--help'].include?(name)
18
- name = 'version' if ['-v', '--version'].include?(name)
19
-
20
- const_name = Helpers.command_to_const(name)
21
- return unless GlobalCommands.const_defined?(const_name)
22
10
 
23
- GlobalCommands.const_get(const_name)
24
- end
11
+ class Exit < StandardError; end
25
12
 
26
13
  attr_reader :command, :aris, :input, :output, :err_output, :prompt
27
14
 
28
- def initialize(argv: ARGV, input: STDIN, output: STDOUT, err_output: STDERR)
15
+ def initialize(argv: ARGV, input: $stdin, output: $stdout, err_output: $stderr)
29
16
  (@command, *remaining_args) = argv
30
17
  @input = input
31
18
  @output = output
@@ -37,7 +24,7 @@ module Abt
37
24
  def perform
38
25
  if command.nil?
39
26
  warn("No command specified, printing help\n\n")
40
- @command = 'help'
27
+ @command = "help"
41
28
  end
42
29
 
43
30
  if global_command?
@@ -83,11 +70,9 @@ module Abt
83
70
  end
84
71
 
85
72
  def process_global_command
86
- command_class = self.class.global_command_class(command)
73
+ command_class = GlobalCommands.command_class(command)
87
74
 
88
- if command_class.nil?
89
- abort "No such global command: #{command}, perhaps you forgot to add an ARI?"
90
- end
75
+ abort("No such global command: #{command}, perhaps you forgot to add an ARI?") if command_class.nil?
91
76
 
92
77
  begin
93
78
  ari = aris.first || Abt::Ari.new
@@ -103,16 +88,14 @@ module Abt
103
88
  @sanitized_piped_args ||= begin
104
89
  input_string = input.read.strip
105
90
 
106
- abort 'No input from pipe' if input_string.nil? || input_string.empty?
91
+ abort("No input from pipe") if input_string.nil? || input_string.empty?
107
92
 
108
93
  # Exclude comment part of piped input lines
109
- lines_without_comments = input_string.lines.map do |line|
110
- line.split(' # ').first
111
- end
94
+ lines_without_comments = input_string.lines.map { |line| line.split(" # ").first }
112
95
 
113
96
  # Allow multiple ARIs on a single piped input line
114
97
  # TODO: Force the user to pick a single ARI
115
- joined_lines = lines_without_comments.join(' ').strip
98
+ joined_lines = lines_without_comments.join(" ").strip
116
99
  joined_lines.split(/\s+/)
117
100
  end
118
101
  end
@@ -122,26 +105,30 @@ module Abt
122
105
 
123
106
  aris.each do |ari|
124
107
  if used_schemes.include?(ari.scheme)
125
- warn "Dropping command for already used scheme: #{ari}"
108
+ warn("Dropping command for already used scheme: #{ari}")
126
109
  next
127
110
  end
128
111
 
129
- command_class = get_command_class(ari.scheme)
130
- next if command_class.nil?
131
-
132
- print_command(command, ari) if output.isatty
133
- begin
134
- command_class.new(ari: ari, cli: self).perform
135
- rescue Exit => e
136
- puts e.message
137
- end
138
-
139
- used_schemes << ari.scheme
112
+ used_schemes << ari.scheme if process_ari(ari)
140
113
  end
141
114
 
142
115
  return unless used_schemes.empty? && output.isatty
143
116
 
144
- abort 'No providers found for command and ARI(s)'
117
+ abort("No providers found for command and ARI(s)")
118
+ end
119
+
120
+ def process_ari(ari)
121
+ command_class = get_command_class(ari.scheme)
122
+ return false if command_class.nil?
123
+
124
+ print_command(command, ari) if output.isatty
125
+ begin
126
+ command_class.new(ari: ari, cli: self).perform
127
+ rescue Exit => e
128
+ puts e.message
129
+ end
130
+
131
+ true
145
132
  end
146
133
 
147
134
  def get_command_class(scheme)
@@ -152,7 +139,7 @@ module Abt
152
139
  end
153
140
 
154
141
  def print_command(name, ari)
155
- warn "===== #{name.upcase} #{ari} ====="
142
+ warn("===== #{name.upcase} #{ari} =====")
156
143
  end
157
144
  end
158
145
  end
@@ -13,15 +13,11 @@ module Abt
13
13
  result = AriList.new
14
14
  rest = arguments.dup
15
15
 
16
- # If the arguments start with "-" it means that we are parsing flags for a global command
17
- if rest.any? && rest.first[0] == '-'
18
- flags = take_flags(rest)
19
-
20
- return [Ari.new(flags: flags)]
21
- end
16
+ # If the first arg is a flag, it's for a global command
17
+ result << Ari.new(flags: take_flags(rest)) if flag?(rest.first)
22
18
 
23
19
  until rest.empty?
24
- (scheme, path) = rest.shift.split(':')
20
+ (scheme, path) = rest.shift.split(":")
25
21
  flags = take_flags(rest)
26
22
 
27
23
  result << Ari.new(scheme: scheme, path: path, flags: flags)
@@ -44,11 +40,11 @@ module Abt
44
40
  end
45
41
 
46
42
  def flag?(part)
47
- part && part[0] == '-'
43
+ part && part[0] == "-"
48
44
  end
49
45
 
50
46
  def delimiter?(part)
51
- part == '--'
47
+ part == "--"
52
48
  end
53
49
  end
54
50
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir.glob("#{File.expand_path(__dir__)}/global_commands/*.rb").sort.each { |file| require file }
4
+
5
+ module Abt
6
+ class Cli
7
+ module GlobalCommands
8
+ def self.command_names
9
+ constants.sort.map { |constant_name| Helpers.const_to_command(constant_name) }
10
+ end
11
+
12
+ def self.command_class(name)
13
+ name = "help" if [nil, "-h", "--help"].include?(name)
14
+ name = "version" if ["-v", "--version"].include?(name)
15
+
16
+ const_name = Helpers.command_to_const(name)
17
+ return unless const_defined?(const_name)
18
+
19
+ const_get(const_name)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -5,11 +5,11 @@ module Abt
5
5
  module GlobalCommands
6
6
  class Commands < Abt::BaseCommand
7
7
  def self.usage
8
- 'abt commands'
8
+ "abt commands"
9
9
  end
10
10
 
11
11
  def self.description
12
- 'List all abt commands'
12
+ "List all abt commands"
13
13
  end
14
14
 
15
15
  attr_reader :cli
@@ -5,11 +5,11 @@ module Abt
5
5
  module GlobalCommands
6
6
  class Examples < Abt::BaseCommand
7
7
  def self.usage
8
- 'abt examples'
8
+ "abt examples"
9
9
  end
10
10
 
11
11
  def self.description
12
- 'Print command examples'
12
+ "Print command examples"
13
13
  end
14
14
 
15
15
  attr_reader :cli
@@ -5,11 +5,11 @@ module Abt
5
5
  module GlobalCommands
6
6
  class Help < Abt::BaseCommand
7
7
  def self.usage
8
- 'abt help'
8
+ "abt help"
9
9
  end
10
10
 
11
11
  def self.description
12
- 'Print abt usage text'
12
+ "Print abt usage text"
13
13
  end
14
14
 
15
15
  attr_reader :cli
@@ -5,11 +5,11 @@ module Abt
5
5
  module GlobalCommands
6
6
  class Readme < Abt::BaseCommand
7
7
  def self.usage
8
- 'abt readme'
8
+ "abt readme"
9
9
  end
10
10
 
11
11
  def self.description
12
- 'Print markdown readme'
12
+ "Print markdown readme"
13
13
  end
14
14
 
15
15
  attr_reader :cli
@@ -5,29 +5,29 @@ module Abt
5
5
  module GlobalCommands
6
6
  class Share < Abt::BaseCommand
7
7
  def self.usage
8
- 'abt share'
8
+ "abt share"
9
9
  end
10
10
 
11
11
  def self.description
12
- 'Prints all project configuration as a single line of ARIs'
12
+ "Prints all project configuration as a single line of ARIs"
13
13
  end
14
14
 
15
15
  attr_reader :cli
16
16
 
17
17
  def perform
18
- warn 'Printing project configuration'
18
+ warn("Printing project configuration")
19
19
  puts share_string
20
20
  end
21
21
 
22
22
  def share_string
23
23
  @share_string ||= begin
24
- aris = Abt.schemes.join(' ')
24
+ aris = Abt.schemes.join(" ")
25
25
 
26
26
  input = StringIO.new(aris)
27
27
  output = StringIO.new
28
- Abt::Cli.new(argv: ['share'], output: output, input: input).perform
28
+ Abt::Cli.new(argv: ["share"], output: output, input: input).perform
29
29
 
30
- output.string.strip.gsub(/\s+/, ' ')
30
+ output.string.strip.gsub(/\s+/, " ")
31
31
  end
32
32
  end
33
33
  end
@@ -5,11 +5,11 @@ module Abt
5
5
  module GlobalCommands
6
6
  class Version < Abt::BaseCommand
7
7
  def self.usage
8
- 'abt version'
8
+ "abt version"
9
9
  end
10
10
 
11
11
  def self.description
12
- 'Print abt version'
12
+ "Print abt version"
13
13
  end
14
14
 
15
15
  attr_reader :cli
@@ -10,7 +10,7 @@ module Abt
10
10
  end
11
11
 
12
12
  def text(question)
13
- output.print "#{question}: "
13
+ output.print("#{question.strip}: ")
14
14
  read_user_input
15
15
  end
16
16
 
@@ -18,25 +18,24 @@ module Abt
18
18
  output.puts text
19
19
 
20
20
  loop do
21
- output.print '(y / n): '
21
+ output.print("(y / n): ")
22
22
 
23
23
  case read_user_input
24
- when 'y', 'Y' then return true
25
- when 'n', 'N' then return false
24
+ when "y", "Y" then return true
25
+ when "n", "N" then return false
26
26
  else
27
- output.puts 'Invalid choice'
28
- next
27
+ output.puts "Invalid choice"
29
28
  end
30
29
  end
31
30
  end
32
31
 
33
- def choice(text, options, nil_option = false)
34
- output.puts "#{text}:"
32
+ def choice(text, options, nil_option: false)
33
+ output.puts "#{text.strip}:"
35
34
 
36
35
  if options.length.zero?
37
- raise Abort, 'No available options' unless nil_option
36
+ raise Abort, "No available options" unless nil_option
38
37
 
39
- output.puts 'No available options'
38
+ output.puts "No available options"
40
39
  return nil
41
40
  end
42
41
 
@@ -44,6 +43,15 @@ module Abt
44
43
  select_options(options, nil_option)
45
44
  end
46
45
 
46
+ def search(text, options)
47
+ output.puts text
48
+
49
+ loop do
50
+ choice = get_search_result(options)
51
+ break choice unless choice.nil?
52
+ end
53
+ end
54
+
47
55
  private
48
56
 
49
57
  def print_options(options)
@@ -69,11 +77,11 @@ module Abt
69
77
  end
70
78
 
71
79
  def read_option_number(options_length, nil_option)
72
- str = '('
73
- str += options_length > 1 ? "1-#{options_length}" : '1'
80
+ str = "("
81
+ str += options_length > 1 ? "1-#{options_length}" : "1"
74
82
  str += nil_option_string(nil_option)
75
- str += '): '
76
- output.print str
83
+ str += "): "
84
+ output.print(str)
77
85
 
78
86
  input = read_user_input
79
87
 
@@ -81,7 +89,7 @@ module Abt
81
89
 
82
90
  option_number = input.to_i
83
91
  if option_number <= 0 || option_number > options_length
84
- output.puts 'Invalid selection'
92
+ output.puts "Invalid selection"
85
93
  return nil
86
94
  end
87
95
 
@@ -89,19 +97,19 @@ module Abt
89
97
  end
90
98
 
91
99
  def nil_option_string(nil_option)
92
- return '' unless nil_option
100
+ return "" unless nil_option
93
101
 
94
102
  ", #{nil_option_character(nil_option)}: #{nil_option_description(nil_option)}"
95
103
  end
96
104
 
97
105
  def nil_option_character(nil_option)
98
- return 'q' if nil_option == true
106
+ return "q" if nil_option == true
99
107
 
100
108
  nil_option[0]
101
109
  end
102
110
 
103
111
  def nil_option_description(nil_option)
104
- return 'back' if nil_option == true
112
+ return "back" if nil_option == true
105
113
  return nil_option if nil_option.is_a?(String)
106
114
 
107
115
  nil_option[1]
@@ -111,11 +119,34 @@ module Abt
111
119
  open(tty_path, &:gets).strip # rubocop:disable Security/Open
112
120
  end
113
121
 
122
+ def get_search_result(options)
123
+ matches = matches_for_string(text("Enter search"), options)
124
+ if matches.empty?
125
+ output.puts("No matches")
126
+ return
127
+ end
128
+
129
+ output.puts("Showing the 10 first matches") if matches.size > 10
130
+ choice("Select a match", matches[0...10], nil_option: true)
131
+ end
132
+
133
+ def matches_for_string(string, options)
134
+ search_string = sanitize_string(string)
135
+
136
+ options.select do |option|
137
+ sanitize_string(option["name"]).include?(search_string)
138
+ end
139
+ end
140
+
141
+ def sanitize_string(string)
142
+ string.downcase.gsub(/[^\w]/, "")
143
+ end
144
+
114
145
  def tty_path
115
146
  @tty_path ||= begin
116
- candidates = ['/dev/tty', 'CON:'] # Unix: '/dev/tty', Windows: 'CON:'
147
+ candidates = ["/dev/tty", "CON:"] # Unix: '/dev/tty', Windows: 'CON:'
117
148
  selected = candidates.find { |candidate| File.exist?(candidate) }
118
- raise Abort, 'Unable to prompt for user input' if selected.nil?
149
+ raise Abort, "Unable to prompt for user input" if selected.nil?
119
150
 
120
151
  selected
121
152
  end