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.
- checksums.yaml +4 -4
- data/bin/abt +3 -3
- data/lib/abt.rb +6 -6
- data/lib/abt/ari.rb +1 -1
- data/lib/abt/ari_list.rb +1 -1
- data/lib/abt/base_command.rb +7 -7
- data/lib/abt/cli.rb +27 -40
- data/lib/abt/cli/arguments_parser.rb +5 -9
- data/lib/abt/cli/global_commands.rb +23 -0
- data/lib/abt/cli/global_commands/commands.rb +2 -2
- data/lib/abt/cli/global_commands/examples.rb +2 -2
- data/lib/abt/cli/global_commands/help.rb +2 -2
- data/lib/abt/cli/global_commands/readme.rb +2 -2
- data/lib/abt/cli/global_commands/share.rb +6 -6
- data/lib/abt/cli/global_commands/version.rb +2 -2
- data/lib/abt/cli/prompt.rb +51 -20
- data/lib/abt/docs.rb +39 -33
- data/lib/abt/docs/cli.rb +3 -3
- data/lib/abt/docs/markdown.rb +5 -5
- data/lib/abt/git_config.rb +4 -6
- data/lib/abt/providers/asana/api.rb +9 -9
- data/lib/abt/providers/asana/base_command.rb +8 -10
- data/lib/abt/providers/asana/commands/add.rb +13 -12
- data/lib/abt/providers/asana/commands/branch_name.rb +8 -8
- data/lib/abt/providers/asana/commands/clear.rb +7 -8
- data/lib/abt/providers/asana/commands/current.rb +14 -14
- data/lib/abt/providers/asana/commands/finalize.rb +11 -12
- data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +11 -11
- data/lib/abt/providers/asana/commands/init.rb +8 -41
- data/lib/abt/providers/asana/commands/pick.rb +17 -17
- data/lib/abt/providers/asana/commands/projects.rb +5 -5
- data/lib/abt/providers/asana/commands/share.rb +5 -5
- data/lib/abt/providers/asana/commands/start.rb +21 -20
- data/lib/abt/providers/asana/commands/tasks.rb +6 -6
- data/lib/abt/providers/asana/configuration.rb +25 -25
- data/lib/abt/providers/asana/path.rb +5 -5
- data/lib/abt/providers/devops/api.rb +12 -12
- data/lib/abt/providers/devops/base_command.rb +10 -10
- data/lib/abt/providers/devops/commands/boards.rb +5 -7
- data/lib/abt/providers/devops/commands/branch_name.rb +9 -9
- data/lib/abt/providers/devops/commands/clear.rb +7 -8
- data/lib/abt/providers/devops/commands/current.rb +17 -17
- data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +13 -13
- data/lib/abt/providers/devops/commands/init.rb +17 -13
- data/lib/abt/providers/devops/commands/pick.rb +11 -11
- data/lib/abt/providers/devops/commands/share.rb +5 -5
- data/lib/abt/providers/devops/commands/{work-items.rb → work_items.rb} +3 -3
- data/lib/abt/providers/devops/configuration.rb +19 -15
- data/lib/abt/providers/devops/path.rb +5 -4
- data/lib/abt/providers/git/commands/branch.rb +17 -19
- data/lib/abt/providers/harvest/api.rb +8 -8
- data/lib/abt/providers/harvest/base_command.rb +6 -8
- data/lib/abt/providers/harvest/commands/clear.rb +7 -8
- data/lib/abt/providers/harvest/commands/current.rb +13 -13
- data/lib/abt/providers/harvest/commands/init.rb +10 -38
- data/lib/abt/providers/harvest/commands/pick.rb +11 -11
- data/lib/abt/providers/harvest/commands/projects.rb +5 -5
- data/lib/abt/providers/harvest/commands/share.rb +5 -5
- data/lib/abt/providers/harvest/commands/start.rb +5 -3
- data/lib/abt/providers/harvest/commands/stop.rb +12 -12
- data/lib/abt/providers/harvest/commands/tasks.rb +7 -7
- data/lib/abt/providers/harvest/commands/track.rb +21 -20
- data/lib/abt/providers/harvest/configuration.rb +18 -18
- data/lib/abt/providers/harvest/path.rb +5 -5
- data/lib/abt/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b8172eca54c77feb083acbc9895bf9f221b69efc1c0b8170d87f250b486286a
|
4
|
+
data.tar.gz: e07e6122c3b3c3bc1307769f5d52d01cb6db9126df0fe10bfb217b940a1eaf12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
9
|
+
abort(e.message)
|
10
10
|
rescue Interrupt
|
11
|
-
abort
|
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
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
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
data/lib/abt/ari_list.rb
CHANGED
data/lib/abt/base_command.rb
CHANGED
@@ -5,11 +5,11 @@ module Abt
|
|
5
5
|
extend Forwardable
|
6
6
|
|
7
7
|
def self.usage
|
8
|
-
raise NotImplementedError,
|
8
|
+
raise NotImplementedError, "Command classes must implement .usage"
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.description
|
12
|
-
raise NotImplementedError,
|
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,
|
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
|
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(
|
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
|
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
|
-
|
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:
|
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 =
|
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 =
|
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
|
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
|
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(
|
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
|
108
|
+
warn("Dropping command for already used scheme: #{ari}")
|
126
109
|
next
|
127
110
|
end
|
128
111
|
|
129
|
-
|
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
|
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
|
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
|
17
|
-
|
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,29 +5,29 @@ module Abt
|
|
5
5
|
module GlobalCommands
|
6
6
|
class Share < Abt::BaseCommand
|
7
7
|
def self.usage
|
8
|
-
|
8
|
+
"abt share"
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.description
|
12
|
-
|
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
|
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: [
|
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
|
data/lib/abt/cli/prompt.rb
CHANGED
@@ -10,7 +10,7 @@ module Abt
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def text(question)
|
13
|
-
output.print
|
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
|
21
|
+
output.print("(y / n): ")
|
22
22
|
|
23
23
|
case read_user_input
|
24
|
-
when
|
25
|
-
when
|
24
|
+
when "y", "Y" then return true
|
25
|
+
when "n", "N" then return false
|
26
26
|
else
|
27
|
-
output.puts
|
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
|
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,
|
36
|
+
raise Abort, "No available options" unless nil_option
|
38
37
|
|
39
|
-
output.puts
|
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}" :
|
80
|
+
str = "("
|
81
|
+
str += options_length > 1 ? "1-#{options_length}" : "1"
|
74
82
|
str += nil_option_string(nil_option)
|
75
|
-
str +=
|
76
|
-
output.print
|
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
|
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
|
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
|
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
|
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 = [
|
147
|
+
candidates = ["/dev/tty", "CON:"] # Unix: '/dev/tty', Windows: 'CON:'
|
117
148
|
selected = candidates.find { |candidate| File.exist?(candidate) }
|
118
|
-
raise Abort,
|
149
|
+
raise Abort, "Unable to prompt for user input" if selected.nil?
|
119
150
|
|
120
151
|
selected
|
121
152
|
end
|