abt-cli 0.0.16 → 0.0.21

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/abt/ari.rb +20 -0
  3. data/lib/abt/ari_list.rb +13 -0
  4. data/lib/abt/base_command.rb +63 -0
  5. data/lib/abt/cli.rb +59 -47
  6. data/lib/abt/cli/arguments_parser.rb +9 -24
  7. data/lib/abt/cli/global_commands/commands.rb +23 -0
  8. data/lib/abt/cli/global_commands/examples.rb +23 -0
  9. data/lib/abt/cli/global_commands/help.rb +23 -0
  10. data/lib/abt/cli/global_commands/readme.rb +23 -0
  11. data/lib/abt/cli/global_commands/share.rb +36 -0
  12. data/lib/abt/cli/global_commands/version.rb +23 -0
  13. data/lib/abt/cli/prompt.rb +5 -4
  14. data/lib/abt/docs.rb +32 -15
  15. data/lib/abt/docs/cli.rb +5 -5
  16. data/lib/abt/docs/markdown.rb +8 -7
  17. data/lib/abt/git_config.rb +20 -36
  18. data/lib/abt/providers/asana/base_command.rb +15 -35
  19. data/lib/abt/providers/asana/commands/add.rb +9 -7
  20. data/lib/abt/providers/asana/commands/branch_name.rb +9 -4
  21. data/lib/abt/providers/asana/commands/clear.rb +2 -0
  22. data/lib/abt/providers/asana/commands/current.rb +19 -34
  23. data/lib/abt/providers/asana/commands/finalize.rb +5 -9
  24. data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +9 -4
  25. data/lib/abt/providers/asana/commands/init.rb +6 -6
  26. data/lib/abt/providers/asana/commands/pick.rb +16 -11
  27. data/lib/abt/providers/asana/commands/projects.rb +1 -1
  28. data/lib/abt/providers/asana/commands/share.rb +5 -7
  29. data/lib/abt/providers/asana/commands/start.rb +14 -12
  30. data/lib/abt/providers/asana/commands/tasks.rb +4 -3
  31. data/lib/abt/providers/asana/configuration.rb +20 -26
  32. data/lib/abt/providers/asana/path.rb +36 -0
  33. data/lib/abt/providers/devops/api.rb +12 -0
  34. data/lib/abt/providers/devops/base_command.rb +15 -40
  35. data/lib/abt/providers/devops/commands/boards.rb +2 -2
  36. data/lib/abt/providers/devops/commands/branch_name.rb +7 -3
  37. data/lib/abt/providers/devops/commands/clear.rb +2 -0
  38. data/lib/abt/providers/devops/commands/current.rb +14 -38
  39. data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +9 -1
  40. data/lib/abt/providers/devops/commands/init.rb +15 -15
  41. data/lib/abt/providers/devops/commands/pick.rb +5 -12
  42. data/lib/abt/providers/devops/commands/share.rb +6 -5
  43. data/lib/abt/providers/devops/commands/work-items.rb +1 -1
  44. data/lib/abt/providers/devops/configuration.rb +17 -46
  45. data/lib/abt/providers/devops/path.rb +50 -0
  46. data/lib/abt/providers/git/commands/branch.rb +22 -16
  47. data/lib/abt/providers/harvest/base_command.rb +16 -34
  48. data/lib/abt/providers/harvest/commands/clear.rb +2 -0
  49. data/lib/abt/providers/harvest/commands/current.rb +24 -31
  50. data/lib/abt/providers/harvest/commands/init.rb +5 -6
  51. data/lib/abt/providers/harvest/commands/pick.rb +3 -4
  52. data/lib/abt/providers/harvest/commands/projects.rb +1 -1
  53. data/lib/abt/providers/harvest/commands/share.rb +5 -7
  54. data/lib/abt/providers/harvest/commands/start.rb +1 -1
  55. data/lib/abt/providers/harvest/commands/stop.rb +7 -7
  56. data/lib/abt/providers/harvest/commands/tasks.rb +4 -1
  57. data/lib/abt/providers/harvest/commands/track.rb +26 -19
  58. data/lib/abt/providers/harvest/configuration.rb +20 -29
  59. data/lib/abt/providers/harvest/path.rb +36 -0
  60. data/lib/abt/version.rb +1 -1
  61. metadata +14 -3
  62. data/lib/abt/cli/base_command.rb +0 -61
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09c4dedacc59650be8d22ae65041e78913fc4405bbb61109ef93217801bafcff'
4
- data.tar.gz: 91f205c4db85e2686b8461c6c2b029a45e6e430c418041aa3ffae725d1ecd16b
3
+ metadata.gz: ce59010855d53bf8b8731a680d7adcd21cef4eb93d421174aee893f27350cb1e
4
+ data.tar.gz: 8ac30f3ada5fcc7c75f7a9a91110340d579fd79d8c6226dd4f92a24bdf070d88
5
5
  SHA512:
6
- metadata.gz: 42f9d332099fdcecdbdf538bd44119b75d643db6399d06fe578d15e5dff664af9dfec59a5ffa1f1235a1b922fa5727d52c20ed0b6a8c4fa795e1750b51f0943d
7
- data.tar.gz: a88ffec46e7331823de6dc89fde11e442ac3c7bd577495a89dd2af20b879675de7fdafada270d1614556d193bb909892fd9622b8b3cd87f2836fab0aa94b1483
6
+ metadata.gz: 0cdbbd886589a06d20281e67a8376b3292cd61e432b7b672c968e2c5730a65707cc60d31d179acdcd7ad2a5eab9ebffe15866e08f5001b1922f291007146038b
7
+ data.tar.gz: d0e568a9db4e57207f1cd8d72c789fea3c456f282c6cc1b4a46694767317a0b5c4055d90d53903779c20cd7ecf3c5a0803b07ebafb03b9e07d5ed99f3be14a88
data/lib/abt/ari.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ class Ari
5
+ attr_reader :scheme, :path, :flags
6
+
7
+ def initialize(scheme: nil, path: nil, flags: [])
8
+ @scheme = scheme
9
+ @path = path
10
+ @flags = flags
11
+ end
12
+
13
+ def to_s
14
+ str = scheme
15
+ str += ":#{path}" if path
16
+
17
+ [str, *flags].join(' ')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ class AriList < Array
5
+ def to_s
6
+ map(&:to_s).join(' -- ')
7
+ end
8
+
9
+ def -(other)
10
+ AriList.new(to_a - other)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ class BaseCommand
5
+ extend Forwardable
6
+
7
+ def self.usage
8
+ raise NotImplementedError, 'Command classes must implement .usage'
9
+ end
10
+
11
+ def self.description
12
+ raise NotImplementedError, 'Command classes must implement .description'
13
+ end
14
+
15
+ def self.flags
16
+ []
17
+ end
18
+
19
+ attr_reader :ari, :cli, :flags
20
+
21
+ def_delegators(:@cli, :warn, :puts, :print, :abort, :exit_with_message)
22
+
23
+ def initialize(ari:, cli:)
24
+ @cli = cli
25
+ @ari = ari
26
+ @flags = parse_flags(ari.flags)
27
+ end
28
+
29
+ def perform
30
+ raise NotImplementedError, 'Command classes must implement #perform'
31
+ end
32
+
33
+ private
34
+
35
+ def parse_flags(flags)
36
+ result = {}
37
+
38
+ flag_parser.parse!(flags.dup, into: result)
39
+
40
+ exit_with_message(flag_parser.help) if result[:help]
41
+
42
+ result
43
+ rescue OptionParser::InvalidOption => e
44
+ abort e.message
45
+ end
46
+
47
+ def flag_parser
48
+ @flag_parser ||= OptionParser.new do |opts|
49
+ opts.banner = <<~TXT
50
+ #{self.class.description}
51
+
52
+ Usage: #{self.class.usage}
53
+ TXT
54
+
55
+ opts.on('-h', '--help', 'Display this help')
56
+
57
+ self.class.flags.each do |(*flag)|
58
+ opts.on(*flag)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
data/lib/abt/cli.rb CHANGED
@@ -1,6 +1,6 @@
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
 
@@ -9,7 +9,21 @@ module Abt
9
9
  class Abort < StandardError; end
10
10
  class Exit < StandardError; end
11
11
 
12
- attr_reader :command, :scheme_arguments, :input, :output, :err_output, :prompt
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
+
23
+ GlobalCommands.const_get(const_name)
24
+ end
25
+
26
+ attr_reader :command, :aris, :input, :output, :err_output, :prompt
13
27
 
14
28
  def initialize(argv: ARGV, input: STDIN, output: STDOUT, err_output: STDERR)
15
29
  (@command, *remaining_args) = argv
@@ -17,19 +31,23 @@ module Abt
17
31
  @output = output
18
32
  @err_output = err_output
19
33
  @prompt = Abt::Cli::Prompt.new(output: err_output)
20
-
21
- @scheme_arguments = ArgumentsParser.new(sanitized_piped_args + remaining_args).parse
34
+ @aris = ArgumentsParser.new(sanitized_piped_args + remaining_args).parse
22
35
  end
23
36
 
24
37
  def perform
25
- return if handle_global_commands!
26
-
27
- abort('No scheme arguments') if scheme_arguments.empty?
38
+ if command.nil?
39
+ warn("No command specified, printing help\n\n")
40
+ @command = 'help'
41
+ end
28
42
 
29
- process_scheme_arguments
43
+ if global_command?
44
+ process_global_command
45
+ else
46
+ process_aris
47
+ end
30
48
  end
31
49
 
32
- def print_scheme_argument(scheme, path, description = nil)
50
+ def print_ari(scheme, path, description = nil)
33
51
  command = "#{scheme}:#{path}"
34
52
  command += " # #{description}" unless description.nil?
35
53
  output.puts command
@@ -57,29 +75,25 @@ module Abt
57
75
 
58
76
  private
59
77
 
60
- def handle_global_commands!
61
- case command
62
- when nil
63
- warn("No command specified\n\n")
64
- puts(Abt::Docs::Cli.help)
65
- true
66
- when '--version', '-v', 'version'
67
- puts(Abt::VERSION)
68
- true
69
- when '--help', '-h', 'help'
70
- puts(Abt::Docs::Cli.help)
71
- true
72
- when 'commands'
73
- puts(Abt::Docs::Cli.commands)
74
- true
75
- when 'examples'
76
- puts(Abt::Docs::Cli.examples)
77
- true
78
- when 'readme'
79
- puts(Abt::Docs::Markdown.readme)
80
- true
81
- else
82
- false
78
+ def global_command?
79
+ return true if aris.empty?
80
+ return true if aris.first.scheme.nil?
81
+
82
+ false
83
+ end
84
+
85
+ def process_global_command
86
+ command_class = self.class.global_command_class(command)
87
+
88
+ if command_class.nil?
89
+ abort "No such global command: #{command}, perhaps you forgot to add an ARI?"
90
+ end
91
+
92
+ begin
93
+ ari = aris.first || Abt::Ari.new
94
+ command_class.new(cli: self, ari: ari).perform
95
+ rescue Exit => e
96
+ puts e.message
83
97
  end
84
98
  end
85
99
 
@@ -96,40 +110,38 @@ module Abt
96
110
  line.split(' # ').first
97
111
  end
98
112
 
99
- # Allow multiple scheme arguments on a single piped input line
100
- # TODO: Force the user to pick a single scheme argument
113
+ # Allow multiple ARIs on a single piped input line
114
+ # TODO: Force the user to pick a single ARI
101
115
  joined_lines = lines_without_comments.join(' ').strip
102
116
  joined_lines.split(/\s+/)
103
117
  end
104
118
  end
105
119
 
106
- def process_scheme_arguments
120
+ def process_aris
107
121
  used_schemes = []
108
- scheme_arguments.each do |scheme_argument|
109
- scheme = scheme_argument.scheme
110
- path = scheme_argument.path
111
122
 
112
- if used_schemes.include?(scheme)
113
- warn "Dropping command for already used scheme: #{scheme_argument}"
123
+ aris.each do |ari|
124
+ if used_schemes.include?(ari.scheme)
125
+ warn "Dropping command for already used scheme: #{ari}"
114
126
  next
115
127
  end
116
128
 
117
- command_class = get_command_class(scheme)
129
+ command_class = get_command_class(ari.scheme)
118
130
  next if command_class.nil?
119
131
 
120
- print_command(command, scheme_argument) if output.isatty
132
+ print_command(command, ari) if output.isatty
121
133
  begin
122
- command_class.new(path: path, cli: self, flags: scheme_argument.flags).perform
134
+ command_class.new(ari: ari, cli: self).perform
123
135
  rescue Exit => e
124
136
  puts e.message
125
137
  end
126
138
 
127
- used_schemes << scheme
139
+ used_schemes << ari.scheme
128
140
  end
129
141
 
130
142
  return unless used_schemes.empty? && output.isatty
131
143
 
132
- abort 'No providers found for command and scheme argument(s)'
144
+ abort 'No providers found for command and ARI(s)'
133
145
  end
134
146
 
135
147
  def get_command_class(scheme)
@@ -139,8 +151,8 @@ module Abt
139
151
  provider.command_class(command)
140
152
  end
141
153
 
142
- def print_command(name, scheme_argument)
143
- warn "===== #{name} #{scheme_argument} =====".upcase
154
+ def print_command(name, ari)
155
+ warn "===== #{name.upcase} #{ari} ====="
144
156
  end
145
157
  end
146
158
  end
@@ -3,28 +3,6 @@
3
3
  module Abt
4
4
  class Cli
5
5
  class ArgumentsParser
6
- class SchemeArgument
7
- attr_reader :scheme, :path, :flags
8
-
9
- def initialize(scheme:, path:, flags:)
10
- @scheme = scheme
11
- @path = path
12
- @flags = flags
13
- end
14
-
15
- def to_s
16
- str = scheme
17
- str += ":#{path}" if path
18
-
19
- [str, *flags].join(' ')
20
- end
21
- end
22
- class SchemeArguments < Array
23
- def to_s
24
- map(&:to_s).join(' -- ')
25
- end
26
- end
27
-
28
6
  attr_reader :arguments
29
7
 
30
8
  def initialize(arguments)
@@ -32,14 +10,21 @@ module Abt
32
10
  end
33
11
 
34
12
  def parse
35
- result = SchemeArguments.new
13
+ result = AriList.new
36
14
  rest = arguments.dup
37
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
22
+
38
23
  until rest.empty?
39
24
  (scheme, path) = rest.shift.split(':')
40
25
  flags = take_flags(rest)
41
26
 
42
- result << SchemeArgument.new(scheme: scheme, path: path, flags: flags)
27
+ result << Ari.new(scheme: scheme, path: path, flags: flags)
43
28
  end
44
29
 
45
30
  result
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ class Cli
5
+ module GlobalCommands
6
+ class Commands < Abt::BaseCommand
7
+ def self.usage
8
+ 'abt commands'
9
+ end
10
+
11
+ def self.description
12
+ 'List all abt commands'
13
+ end
14
+
15
+ attr_reader :cli
16
+
17
+ def perform
18
+ puts(Abt::Docs::Cli.commands)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ class Cli
5
+ module GlobalCommands
6
+ class Examples < Abt::BaseCommand
7
+ def self.usage
8
+ 'abt examples'
9
+ end
10
+
11
+ def self.description
12
+ 'Print command examples'
13
+ end
14
+
15
+ attr_reader :cli
16
+
17
+ def perform
18
+ puts(Abt::Docs::Cli.examples)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ class Cli
5
+ module GlobalCommands
6
+ class Help < Abt::BaseCommand
7
+ def self.usage
8
+ 'abt help'
9
+ end
10
+
11
+ def self.description
12
+ 'Print abt usage text'
13
+ end
14
+
15
+ attr_reader :cli
16
+
17
+ def perform
18
+ puts(Abt::Docs::Cli.help)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ class Cli
5
+ module GlobalCommands
6
+ class Readme < Abt::BaseCommand
7
+ def self.usage
8
+ 'abt readme'
9
+ end
10
+
11
+ def self.description
12
+ 'Print markdown readme'
13
+ end
14
+
15
+ attr_reader :cli
16
+
17
+ def perform
18
+ puts(Abt::Docs::Markdown.readme)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ class Cli
5
+ module GlobalCommands
6
+ class Share < Abt::BaseCommand
7
+ def self.usage
8
+ 'abt share'
9
+ end
10
+
11
+ def self.description
12
+ 'Prints all project configuration as a single line of ARIs'
13
+ end
14
+
15
+ attr_reader :cli
16
+
17
+ def perform
18
+ warn 'Printing project configuration'
19
+ puts share_string
20
+ end
21
+
22
+ def share_string
23
+ @share_string ||= begin
24
+ aris = Abt.schemes.join(' ')
25
+
26
+ input = StringIO.new(aris)
27
+ output = StringIO.new
28
+ Abt::Cli.new(argv: ['share'], output: output, input: input).perform
29
+
30
+ output.string.strip.gsub(/\s+/, ' ')
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end