abt-cli 0.0.17 → 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 +20 -0
- data/lib/abt/ari_list.rb +13 -0
- data/lib/abt/base_command.rb +63 -0
- data/lib/abt/cli.rb +58 -59
- data/lib/abt/cli/arguments_parser.rb +8 -27
- data/lib/abt/cli/global_commands.rb +23 -0
- data/lib/abt/cli/global_commands/commands.rb +23 -0
- data/lib/abt/cli/global_commands/examples.rb +23 -0
- data/lib/abt/cli/global_commands/help.rb +23 -0
- data/lib/abt/cli/global_commands/readme.rb +23 -0
- data/lib/abt/cli/global_commands/share.rb +36 -0
- data/lib/abt/cli/global_commands/version.rb +23 -0
- data/lib/abt/cli/prompt.rb +52 -20
- data/lib/abt/docs.rb +48 -25
- data/lib/abt/docs/cli.rb +7 -7
- data/lib/abt/docs/markdown.rb +13 -12
- data/lib/abt/git_config.rb +21 -39
- data/lib/abt/providers/asana/api.rb +9 -9
- data/lib/abt/providers/asana/base_command.rb +16 -38
- data/lib/abt/providers/asana/commands/add.rb +18 -15
- data/lib/abt/providers/asana/commands/branch_name.rb +13 -8
- data/lib/abt/providers/asana/commands/clear.rb +8 -7
- data/lib/abt/providers/asana/commands/current.rb +23 -38
- data/lib/abt/providers/asana/commands/finalize.rb +11 -16
- data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +14 -9
- data/lib/abt/providers/asana/commands/init.rb +8 -41
- data/lib/abt/providers/asana/commands/pick.rb +22 -17
- data/lib/abt/providers/asana/commands/projects.rb +5 -5
- data/lib/abt/providers/asana/commands/share.rb +6 -8
- data/lib/abt/providers/asana/commands/start.rb +26 -23
- data/lib/abt/providers/asana/commands/tasks.rb +6 -5
- data/lib/abt/providers/asana/configuration.rb +34 -40
- data/lib/abt/providers/asana/path.rb +36 -0
- data/lib/abt/providers/devops/api.rb +23 -11
- data/lib/abt/providers/devops/base_command.rb +18 -43
- data/lib/abt/providers/devops/commands/boards.rb +5 -7
- data/lib/abt/providers/devops/commands/branch_name.rb +14 -10
- data/lib/abt/providers/devops/commands/clear.rb +8 -7
- data/lib/abt/providers/devops/commands/current.rb +25 -49
- data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +20 -12
- data/lib/abt/providers/devops/commands/init.rb +29 -25
- data/lib/abt/providers/devops/commands/pick.rb +11 -18
- data/lib/abt/providers/devops/commands/share.rb +7 -6
- data/lib/abt/providers/devops/commands/{work-items.rb → work_items.rb} +3 -3
- data/lib/abt/providers/devops/configuration.rb +31 -56
- data/lib/abt/providers/devops/path.rb +51 -0
- data/lib/abt/providers/git/commands/branch.rb +29 -25
- data/lib/abt/providers/harvest/api.rb +8 -8
- data/lib/abt/providers/harvest/base_command.rb +18 -38
- data/lib/abt/providers/harvest/commands/clear.rb +8 -7
- data/lib/abt/providers/harvest/commands/current.rb +28 -35
- data/lib/abt/providers/harvest/commands/init.rb +10 -39
- data/lib/abt/providers/harvest/commands/pick.rb +11 -12
- data/lib/abt/providers/harvest/commands/projects.rb +5 -5
- data/lib/abt/providers/harvest/commands/share.rb +6 -8
- data/lib/abt/providers/harvest/commands/start.rb +5 -3
- data/lib/abt/providers/harvest/commands/stop.rb +13 -13
- data/lib/abt/providers/harvest/commands/tasks.rb +9 -6
- data/lib/abt/providers/harvest/commands/track.rb +40 -32
- data/lib/abt/providers/harvest/configuration.rb +28 -37
- data/lib/abt/providers/harvest/path.rb +36 -0
- data/lib/abt/version.rb +1 -1
- metadata +18 -6
- data/lib/abt/cli/base_command.rb +0 -61
@@ -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
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Abt
|
4
|
+
class Cli
|
5
|
+
module GlobalCommands
|
6
|
+
class Version < Abt::BaseCommand
|
7
|
+
def self.usage
|
8
|
+
"abt version"
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.description
|
12
|
+
"Print abt version"
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :cli
|
16
|
+
|
17
|
+
def perform
|
18
|
+
puts(Abt::VERSION)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
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,10 +77,11 @@ module Abt
|
|
69
77
|
end
|
70
78
|
|
71
79
|
def read_option_number(options_length, nil_option)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
80
|
+
str = "("
|
81
|
+
str += options_length > 1 ? "1-#{options_length}" : "1"
|
82
|
+
str += nil_option_string(nil_option)
|
83
|
+
str += "): "
|
84
|
+
output.print(str)
|
76
85
|
|
77
86
|
input = read_user_input
|
78
87
|
|
@@ -80,7 +89,7 @@ module Abt
|
|
80
89
|
|
81
90
|
option_number = input.to_i
|
82
91
|
if option_number <= 0 || option_number > options_length
|
83
|
-
output.puts
|
92
|
+
output.puts "Invalid selection"
|
84
93
|
return nil
|
85
94
|
end
|
86
95
|
|
@@ -88,19 +97,19 @@ module Abt
|
|
88
97
|
end
|
89
98
|
|
90
99
|
def nil_option_string(nil_option)
|
91
|
-
return
|
100
|
+
return "" unless nil_option
|
92
101
|
|
93
102
|
", #{nil_option_character(nil_option)}: #{nil_option_description(nil_option)}"
|
94
103
|
end
|
95
104
|
|
96
105
|
def nil_option_character(nil_option)
|
97
|
-
return
|
106
|
+
return "q" if nil_option == true
|
98
107
|
|
99
108
|
nil_option[0]
|
100
109
|
end
|
101
110
|
|
102
111
|
def nil_option_description(nil_option)
|
103
|
-
return
|
112
|
+
return "back" if nil_option == true
|
104
113
|
return nil_option if nil_option.is_a?(String)
|
105
114
|
|
106
115
|
nil_option[1]
|
@@ -110,11 +119,34 @@ module Abt
|
|
110
119
|
open(tty_path, &:gets).strip # rubocop:disable Security/Open
|
111
120
|
end
|
112
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
|
+
|
113
145
|
def tty_path
|
114
146
|
@tty_path ||= begin
|
115
|
-
candidates = [
|
147
|
+
candidates = ["/dev/tty", "CON:"] # Unix: '/dev/tty', Windows: 'CON:'
|
116
148
|
selected = candidates.find { |candidate| File.exist?(candidate) }
|
117
|
-
raise Abort,
|
149
|
+
raise Abort, "Unable to prompt for user input" if selected.nil?
|
118
150
|
|
119
151
|
selected
|
120
152
|
end
|
data/lib/abt/docs.rb
CHANGED
@@ -9,48 +9,71 @@ module Abt
|
|
9
9
|
class << self
|
10
10
|
def basic_examples
|
11
11
|
{
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
"Getting started:" => {
|
13
|
+
"abt init asana harvest" => "Setup asana and harvest project for local git repo",
|
14
|
+
"abt pick harvest" => "Pick harvest task. This will likely stay the same throughout the project",
|
15
|
+
"abt pick asana | abt start harvest" => "Pick asana task and start tracking time",
|
16
|
+
"abt stop harvest" => "Stop time tracker",
|
17
|
+
"abt start asana harvest" => "Continue working, e.g., after a break",
|
18
|
+
"abt finalize asana" => "Finalize the selected asana task"
|
19
19
|
}
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
|
-
def extended_examples
|
23
|
+
def extended_examples # rubocop:disable Metrics/MethodLength
|
24
24
|
{
|
25
|
-
|
26
|
-
|
27
|
-
'abt pick harvest -d | abt track harvest -c "Name of meeting"' =>
|
25
|
+
"Tracking meetings (without switching current task setting):" => {
|
26
|
+
"abt pick asana -d | abt track harvest" => "Track on asana meeting task",
|
27
|
+
'abt pick harvest -d | abt track harvest -c "Name of meeting"' => "Track on separate harvest-task"
|
28
28
|
},
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
"Many commands output ARIs that can be piped into other commands:" => {
|
30
|
+
"abt tasks asana | grep -i <name of task>" => nil,
|
31
|
+
"abt tasks asana | grep -i <name of task> | abt start" => nil
|
32
32
|
},
|
33
|
-
|
34
|
-
'abt share asana harvest | tr "\n" " "' =>
|
35
|
-
'abt share asana harvest | tr "\n" " " | pbcopy' =>
|
36
|
-
|
33
|
+
"Sharing ARIs:" => {
|
34
|
+
'abt share asana harvest | tr "\n" " "' => "Print current asana and harvest ARIs on a single line",
|
35
|
+
'abt share asana harvest | tr "\n" " " | pbcopy' => "Copy ARIs to clipboard (mac only)",
|
36
|
+
"abt start <ARIs from coworker>" => "Work on a task your coworker shared with you",
|
37
|
+
"abt current <ARIs from coworker> | abt start" => "Set task as current, then start it"
|
37
38
|
},
|
38
|
-
|
39
|
-
'abt start harvest -c "comment"' =>
|
40
|
-
'abt start harvest -c "comment" -- asana' =>
|
41
|
-
|
39
|
+
"Flags:" => {
|
40
|
+
'abt start harvest -c "comment"' => "Add command flags after ARIs",
|
41
|
+
'abt start harvest -c "comment" -- asana' =>
|
42
|
+
"Use -- to end a list of flags, so that it can be followed by another ARI",
|
43
|
+
'abt pick harvest | abt start -c "comment"' =>
|
44
|
+
"Flags placed directly after a command applies to the piped in ARI"
|
42
45
|
}
|
43
46
|
}
|
44
47
|
end
|
45
48
|
|
46
49
|
def providers
|
47
|
-
@providers ||=
|
48
|
-
|
50
|
+
@providers ||= begin
|
51
|
+
providers = {}
|
52
|
+
|
53
|
+
providers["Global"] = global_command_definitions
|
54
|
+
|
55
|
+
Abt.schemes.sort.each_with_object(providers) do |scheme, definition|
|
56
|
+
definition[scheme] = command_definitions(scheme)
|
57
|
+
end
|
58
|
+
|
59
|
+
providers
|
49
60
|
end
|
50
61
|
end
|
51
62
|
|
52
63
|
private
|
53
64
|
|
65
|
+
def global_command_definitions
|
66
|
+
global_command_names = Abt::Cli::GlobalCommands.command_names
|
67
|
+
global_command_names.each_with_object({}) do |name, definition|
|
68
|
+
command_class = Abt::Cli::GlobalCommands.command_class(name)
|
69
|
+
full_name = "abt #{name}"
|
70
|
+
|
71
|
+
if command_class.respond_to?(:usage) && command_class.respond_to?(:description)
|
72
|
+
definition[full_name] = [command_class.usage.strip, command_class.description.strip]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
54
77
|
def command_definitions(scheme)
|
55
78
|
provider = Abt.scheme_provider(scheme)
|
56
79
|
provider.command_names.each_with_object({}) do |name, definition|
|
@@ -58,7 +81,7 @@ module Abt
|
|
58
81
|
full_name = "abt #{name} #{scheme}"
|
59
82
|
|
60
83
|
if command_class.respond_to?(:usage) && command_class.respond_to?(:description)
|
61
|
-
definition[full_name] = [command_class.usage, command_class.description]
|
84
|
+
definition[full_name] = [command_class.usage.strip, command_class.description.strip]
|
62
85
|
end
|
63
86
|
end
|
64
87
|
end
|
data/lib/abt/docs/cli.rb
CHANGED
@@ -8,10 +8,10 @@ module Abt
|
|
8
8
|
<<~TXT
|
9
9
|
Usage: #{usage_line}
|
10
10
|
|
11
|
-
<command>
|
12
|
-
<
|
13
|
-
|
14
|
-
<options>
|
11
|
+
<command> Name of command to execute, e.g. start, finalize etc.
|
12
|
+
<ARI> A URI-like resource identifier with a scheme and an optional path
|
13
|
+
in the format: <scheme>[:<path>]. E.g., harvest:11111111/22222222
|
14
|
+
<options> Optional flags for the command and ARI
|
15
15
|
|
16
16
|
#{formatted_examples(Docs.basic_examples)}
|
17
17
|
|
@@ -45,14 +45,14 @@ module Abt
|
|
45
45
|
private
|
46
46
|
|
47
47
|
def usage_line
|
48
|
-
|
48
|
+
"abt <command> [<ARI>] [<options> --] [<ARI>] ..."
|
49
49
|
end
|
50
50
|
|
51
51
|
def formatted_examples(example_groups)
|
52
52
|
lines = []
|
53
53
|
|
54
54
|
example_groups.each_with_index do |(title, examples), index|
|
55
|
-
lines <<
|
55
|
+
lines << "" unless index.zero?
|
56
56
|
lines << title
|
57
57
|
|
58
58
|
max_length = examples.keys.map(&:length).max
|
@@ -68,7 +68,7 @@ module Abt
|
|
68
68
|
lines = []
|
69
69
|
|
70
70
|
Docs.providers.each_with_index do |(scheme, commands_definition), index|
|
71
|
-
lines <<
|
71
|
+
lines << "" unless index.zero?
|
72
72
|
lines << "#{inflector.humanize(scheme)}:"
|
73
73
|
|
74
74
|
max_length = commands_definition.keys.map(&:length).max
|
data/lib/abt/docs/markdown.rb
CHANGED
@@ -15,27 +15,28 @@ module Abt
|
|
15
15
|
|
16
16
|
## How does abt work?
|
17
17
|
|
18
|
-
Abt
|
18
|
+
Abt is a hybrid of having small scripts each doing one thing:
|
19
19
|
- `start-asana --project-gid xxxx --task-gid yyyy`
|
20
20
|
- `start-harvest --project-id aaaa --task-id bbbb`
|
21
21
|
|
22
|
-
And having a single highly advanced script that does everything:
|
22
|
+
And having a single highly advanced script that does everything with a single command:
|
23
23
|
- `start xxxx/yyyy aaaa/bbbb`
|
24
24
|
|
25
|
-
Abt looks like one
|
25
|
+
Abt looks like one command, but works like a bunch of light scripts:
|
26
26
|
- `abt start asana:xxxx/yyyy harvest:aaaa/bbbb`
|
27
27
|
|
28
28
|
## Usage
|
29
|
-
`abt <command> [<
|
29
|
+
`abt <command> [<ARI>] [<options> --] [<ARI>] ...`
|
30
30
|
|
31
31
|
Definitions:
|
32
32
|
- `<command>`: Name of command to execute, e.g. `start`, `finalize` etc.
|
33
|
-
- `<
|
34
|
-
- `<options>`: Optional flags for the command and
|
33
|
+
- `<ARI>`: A URI-like resource identifier with a scheme and an optional path in the format: `<scheme>[:<path>]`. E.g., `harvest:11111111/22222222`
|
34
|
+
- `<options>`: Optional flags for the command and ARI
|
35
35
|
|
36
36
|
#{example_commands}
|
37
37
|
|
38
|
-
##
|
38
|
+
## Commands:
|
39
|
+
|
39
40
|
Some commands have `[options]`. Run such a command with `--help` flag to view supported flags, e.g: `abt track harvest -h`
|
40
41
|
|
41
42
|
#{provider_commands}
|
@@ -51,11 +52,11 @@ module Abt
|
|
51
52
|
|
52
53
|
examples = Docs.basic_examples.merge(Docs.extended_examples)
|
53
54
|
examples.each_with_index do |(title, commands), index|
|
54
|
-
lines <<
|
55
|
+
lines << "" unless index.zero?
|
55
56
|
lines << title
|
56
57
|
|
57
58
|
commands.each do |(command, description)|
|
58
|
-
formatted_description = description.nil? ?
|
59
|
+
formatted_description = description.nil? ? "" : ": #{description}"
|
59
60
|
lines << "- `#{command}`#{formatted_description}"
|
60
61
|
end
|
61
62
|
end
|
@@ -67,10 +68,10 @@ module Abt
|
|
67
68
|
lines = []
|
68
69
|
|
69
70
|
Docs.providers.each_with_index do |(scheme, commands), index|
|
70
|
-
lines <<
|
71
|
+
lines << "" unless index.zero?
|
71
72
|
lines << "### #{inflector.humanize(scheme)}"
|
72
|
-
lines <<
|
73
|
-
lines <<
|
73
|
+
lines << "| Command | Description |"
|
74
|
+
lines << "| :------ | :---------- |"
|
74
75
|
|
75
76
|
max_length = commands.values.map(&:first).map(&:length).max
|
76
77
|
|