abt-cli 0.0.21 → 0.0.22

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