abt-cli 0.0.21 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/bin/abt +3 -3
  3. data/lib/abt.rb +11 -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 +55 -49
  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 +71 -56
  17. data/lib/abt/directory_config.rb +25 -0
  18. data/lib/abt/docs.rb +39 -33
  19. data/lib/abt/docs/cli.rb +3 -3
  20. data/lib/abt/docs/markdown.rb +10 -7
  21. data/lib/abt/git_config.rb +4 -6
  22. data/lib/abt/helpers.rb +26 -8
  23. data/lib/abt/providers/asana/api.rb +9 -9
  24. data/lib/abt/providers/asana/base_command.rb +12 -10
  25. data/lib/abt/providers/asana/commands/add.rb +13 -12
  26. data/lib/abt/providers/asana/commands/branch_name.rb +8 -8
  27. data/lib/abt/providers/asana/commands/clear.rb +7 -8
  28. data/lib/abt/providers/asana/commands/current.rb +14 -15
  29. data/lib/abt/providers/asana/commands/finalize.rb +17 -14
  30. data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +18 -16
  31. data/lib/abt/providers/asana/commands/init.rb +8 -41
  32. data/lib/abt/providers/asana/commands/pick.rb +22 -26
  33. data/lib/abt/providers/asana/commands/projects.rb +5 -5
  34. data/lib/abt/providers/asana/commands/share.rb +5 -5
  35. data/lib/abt/providers/asana/commands/start.rb +28 -21
  36. data/lib/abt/providers/asana/commands/tasks.rb +6 -6
  37. data/lib/abt/providers/asana/configuration.rb +45 -29
  38. data/lib/abt/providers/asana/path.rb +6 -6
  39. data/lib/abt/providers/devops/api.rb +12 -12
  40. data/lib/abt/providers/devops/base_command.rb +14 -10
  41. data/lib/abt/providers/devops/commands/boards.rb +5 -7
  42. data/lib/abt/providers/devops/commands/branch_name.rb +9 -9
  43. data/lib/abt/providers/devops/commands/clear.rb +7 -8
  44. data/lib/abt/providers/devops/commands/current.rb +17 -18
  45. data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +21 -19
  46. data/lib/abt/providers/devops/commands/init.rb +21 -14
  47. data/lib/abt/providers/devops/commands/pick.rb +37 -19
  48. data/lib/abt/providers/devops/commands/share.rb +5 -5
  49. data/lib/abt/providers/devops/commands/{work-items.rb → work_items.rb} +3 -3
  50. data/lib/abt/providers/devops/configuration.rb +15 -15
  51. data/lib/abt/providers/devops/path.rb +7 -6
  52. data/lib/abt/providers/git/commands/branch.rb +23 -21
  53. data/lib/abt/providers/harvest/api.rb +8 -8
  54. data/lib/abt/providers/harvest/base_command.rb +10 -8
  55. data/lib/abt/providers/harvest/commands/clear.rb +7 -8
  56. data/lib/abt/providers/harvest/commands/current.rb +13 -14
  57. data/lib/abt/providers/harvest/commands/init.rb +10 -39
  58. data/lib/abt/providers/harvest/commands/pick.rb +15 -11
  59. data/lib/abt/providers/harvest/commands/projects.rb +5 -5
  60. data/lib/abt/providers/harvest/commands/share.rb +5 -5
  61. data/lib/abt/providers/harvest/commands/start.rb +5 -3
  62. data/lib/abt/providers/harvest/commands/stop.rb +12 -12
  63. data/lib/abt/providers/harvest/commands/tasks.rb +7 -7
  64. data/lib/abt/providers/harvest/commands/track.rb +52 -37
  65. data/lib/abt/providers/harvest/configuration.rb +18 -18
  66. data/lib/abt/providers/harvest/path.rb +6 -6
  67. data/lib/abt/version.rb +1 -1
  68. metadata +7 -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: ed527a89749355f223b94daa60d63b91c78ae98ab6976c3470ec6ca42cbcff27
4
+ data.tar.gz: aed24bd58e30bfbbdc574532eb97044cd8e108851c2586ac407c0eb42a2deb28
5
5
  SHA512:
6
- metadata.gz: 0cdbbd886589a06d20281e67a8376b3292cd61e432b7b672c968e2c5730a65707cc60d31d179acdcd7ad2a5eab9ebffe15866e08f5001b1922f291007146038b
7
- data.tar.gz: d0e568a9db4e57207f1cd8d72c789fea3c456f282c6cc1b4a46694767317a0b5c4055d90d53903779c20cd7ecf3c5a0803b07ebafb03b9e07d5ed99f3be14a88
6
+ metadata.gz: 6d615f241ac406df5f89cc79ad36f19b0554602f6eb3e20e2f01ba0143595ea6e748c727ccedfeecd1a826c46e031acc7160a3b0ee7462027157a357d730de35
7
+ data.tar.gz: 2b9e500f77e181f4198ac17939fc1753f9a7105682783b005d780ec4da61c8af43aa3e986bba34e1df4f5173bde47bd0e97e042f293edb713a364d2a9c1c71b6
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.strip)
10
10
  rescue Interrupt
11
- abort 'Aborted'
11
+ exit 130
12
12
  end
data/lib/abt.rb CHANGED
@@ -1,11 +1,12 @@
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
+ require "yaml"
9
10
 
10
11
  Dir.glob("#{File.dirname(File.absolute_path(__FILE__))}/abt/*.rb").sort.each do |file|
11
12
  require file
@@ -22,4 +23,8 @@ module Abt
22
23
  const_name = Helpers.command_to_const(scheme)
23
24
  Providers.const_get(const_name) if Providers.const_defined?(const_name)
24
25
  end
26
+
27
+ def self.directory_config
28
+ @directory_config ||= Abt::DirectoryConfig.new
29
+ end
25
30
  end
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,50 +1,35 @@
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
- class Cli
8
+ class Cli # rubocop:disable Metrics/ClassLength
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
10
 
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
11
+ class Exit < StandardError; end
25
12
 
26
- attr_reader :command, :aris, :input, :output, :err_output, :prompt
13
+ attr_reader :command, :remaining_args, :input, :output, :err_output, :prompt
27
14
 
28
- def initialize(argv: ARGV, input: STDIN, output: STDOUT, err_output: STDERR)
29
- (@command, *remaining_args) = argv
15
+ def initialize(argv: ARGV, input: $stdin, output: $stdout, err_output: $stderr)
16
+ (@command, *@remaining_args) = argv
30
17
  @input = input
31
18
  @output = output
32
19
  @err_output = err_output
33
20
  @prompt = Abt::Cli::Prompt.new(output: err_output)
34
- @aris = ArgumentsParser.new(sanitized_piped_args + remaining_args).parse
35
21
  end
36
22
 
37
23
  def perform
38
24
  if command.nil?
39
25
  warn("No command specified, printing help\n\n")
40
- @command = 'help'
26
+ @command = "help"
41
27
  end
42
28
 
43
- if global_command?
44
- process_global_command
45
- else
46
- process_aris
47
- end
29
+ return process_alias if alias?
30
+ return process_global_command if global_command?
31
+
32
+ process_aris
48
33
  end
49
34
 
50
35
  def print_ari(scheme, path, description = nil)
@@ -73,8 +58,29 @@ module Abt
73
58
  raise Exit, message
74
59
  end
75
60
 
61
+ def aris
62
+ @aris ||= ArgumentsParser.new(sanitized_piped_args + remaining_args).parse
63
+ end
64
+
76
65
  private
77
66
 
67
+ def alias?
68
+ command[0] == "@"
69
+ end
70
+
71
+ def process_alias
72
+ matching_alias = Abt.directory_config.dig("aliases", command[1..-1])
73
+
74
+ abort("No such alias #{command}") if matching_alias.nil?
75
+
76
+ with_args = matching_alias.sub("$@", remaining_args.join(" "))
77
+ with_program_name = with_args.gsub("$0", $PROGRAM_NAME).strip
78
+ humanized = with_args.gsub("$0", "abt").strip
79
+
80
+ warn(humanized)
81
+ system(with_program_name)
82
+ end
83
+
78
84
  def global_command?
79
85
  return true if aris.empty?
80
86
  return true if aris.first.scheme.nil?
@@ -83,11 +89,9 @@ module Abt
83
89
  end
84
90
 
85
91
  def process_global_command
86
- command_class = self.class.global_command_class(command)
92
+ command_class = GlobalCommands.command_class(command)
87
93
 
88
- if command_class.nil?
89
- abort "No such global command: #{command}, perhaps you forgot to add an ARI?"
90
- end
94
+ abort("No such global command: #{command}, perhaps you forgot to add an ARI?") if command_class.nil?
91
95
 
92
96
  begin
93
97
  ari = aris.first || Abt::Ari.new
@@ -103,16 +107,14 @@ module Abt
103
107
  @sanitized_piped_args ||= begin
104
108
  input_string = input.read.strip
105
109
 
106
- abort 'No input from pipe' if input_string.nil? || input_string.empty?
110
+ abort("No input from pipe") if input_string.nil? || input_string.empty?
107
111
 
108
112
  # Exclude comment part of piped input lines
109
- lines_without_comments = input_string.lines.map do |line|
110
- line.split(' # ').first
111
- end
113
+ lines_without_comments = input_string.lines.map { |line| line.split(" # ").first }
112
114
 
113
115
  # Allow multiple ARIs on a single piped input line
114
116
  # TODO: Force the user to pick a single ARI
115
- joined_lines = lines_without_comments.join(' ').strip
117
+ joined_lines = lines_without_comments.join(" ").strip
116
118
  joined_lines.split(/\s+/)
117
119
  end
118
120
  end
@@ -122,26 +124,30 @@ module Abt
122
124
 
123
125
  aris.each do |ari|
124
126
  if used_schemes.include?(ari.scheme)
125
- warn "Dropping command for already used scheme: #{ari}"
127
+ warn("Dropping command for already used scheme: #{ari}")
126
128
  next
127
129
  end
128
130
 
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
131
+ used_schemes << ari.scheme if process_ari(ari)
140
132
  end
141
133
 
142
134
  return unless used_schemes.empty? && output.isatty
143
135
 
144
- abort 'No providers found for command and ARI(s)'
136
+ abort("No providers found for command and ARI(s)")
137
+ end
138
+
139
+ def process_ari(ari)
140
+ command_class = get_command_class(ari.scheme)
141
+ return false if command_class.nil?
142
+
143
+ print_command(command, ari) if output.isatty
144
+ begin
145
+ command_class.new(ari: ari, cli: self).perform
146
+ rescue Exit => e
147
+ puts e.message
148
+ end
149
+
150
+ true
145
151
  end
146
152
 
147
153
  def get_command_class(scheme)
@@ -152,7 +158,7 @@ module Abt
152
158
  end
153
159
 
154
160
  def print_command(name, ari)
155
- warn "===== #{name.upcase} #{ari} ====="
161
+ warn("===== #{name.upcase} #{ari} =====")
156
162
  end
157
163
  end
158
164
  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