abt-cli 0.0.13 → 0.0.18
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 +1 -1
- data/lib/abt.rb +6 -3
- data/lib/abt/cli.rb +91 -53
- data/lib/abt/cli/arguments_parser.rb +70 -0
- data/lib/abt/cli/base_command.rb +61 -0
- data/lib/abt/cli/{dialogs.rb → prompt.rb} +37 -18
- data/lib/abt/docs.rb +30 -24
- data/lib/abt/docs/cli.rb +42 -11
- data/lib/abt/docs/markdown.rb +38 -11
- data/lib/abt/git_config.rb +25 -14
- data/lib/abt/helpers.rb +1 -1
- data/lib/abt/providers/asana/base_command.rb +13 -13
- data/lib/abt/providers/asana/commands/add.rb +6 -6
- data/lib/abt/providers/asana/commands/branch_name.rb +44 -0
- data/lib/abt/providers/asana/commands/clear.rb +17 -6
- data/lib/abt/providers/asana/commands/current.rb +3 -3
- data/lib/abt/providers/asana/commands/finalize.rb +3 -3
- data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +3 -3
- data/lib/abt/providers/asana/commands/init.rb +5 -5
- data/lib/abt/providers/asana/commands/pick.rb +16 -8
- data/lib/abt/providers/asana/commands/projects.rb +3 -3
- data/lib/abt/providers/asana/commands/share.rb +5 -5
- data/lib/abt/providers/asana/commands/start.rb +14 -8
- data/lib/abt/providers/asana/commands/tasks.rb +3 -3
- data/lib/abt/providers/asana/configuration.rb +8 -16
- data/lib/abt/providers/devops/base_command.rb +14 -15
- data/lib/abt/providers/devops/commands/boards.rb +6 -4
- data/lib/abt/providers/devops/commands/branch_name.rb +45 -0
- data/lib/abt/providers/devops/commands/clear.rb +17 -6
- data/lib/abt/providers/devops/commands/current.rb +3 -3
- data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +3 -3
- data/lib/abt/providers/devops/commands/init.rb +5 -5
- data/lib/abt/providers/devops/commands/pick.rb +14 -7
- data/lib/abt/providers/devops/commands/share.rb +4 -4
- data/lib/abt/providers/devops/commands/work-items.rb +3 -3
- data/lib/abt/providers/devops/configuration.rb +7 -15
- data/lib/abt/providers/git.rb +19 -0
- data/lib/abt/providers/git/commands/branch.rb +74 -0
- data/lib/abt/providers/harvest/base_command.rb +13 -13
- data/lib/abt/providers/harvest/commands/clear.rb +17 -6
- data/lib/abt/providers/harvest/commands/current.rb +3 -3
- data/lib/abt/providers/harvest/commands/init.rb +5 -5
- data/lib/abt/providers/harvest/commands/pick.rb +15 -7
- data/lib/abt/providers/harvest/commands/projects.rb +3 -3
- data/lib/abt/providers/harvest/commands/share.rb +5 -5
- data/lib/abt/providers/harvest/commands/start.rb +6 -42
- data/lib/abt/providers/harvest/commands/stop.rb +3 -3
- data/lib/abt/providers/harvest/commands/tasks.rb +3 -3
- data/lib/abt/providers/harvest/commands/track.rb +49 -11
- data/lib/abt/providers/harvest/configuration.rb +7 -13
- data/lib/abt/version.rb +1 -1
- metadata +9 -7
- data/lib/abt/cli/io.rb +0 -23
- data/lib/abt/providers/asana/commands/clear_global.rb +0 -24
- data/lib/abt/providers/devops/commands/clear_global.rb +0 -24
- data/lib/abt/providers/harvest/commands/clear_global.rb +0 -24
@@ -5,17 +5,28 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Clear < BaseCommand
|
8
|
-
def self.
|
9
|
-
'clear asana'
|
8
|
+
def self.usage
|
9
|
+
'abt clear asana'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
'Clear
|
13
|
+
'Clear asana configuration'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
16
|
+
def self.flags
|
17
|
+
[
|
18
|
+
['-g', '--global', 'Clear global instead of local asana configuration (credentials etc.)'],
|
19
|
+
['-a', '--all', 'Clear all asana configuration']
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
def perform
|
24
|
+
if flags[:global] && flags[:all]
|
25
|
+
abort('Flags --global and --all cannot be used at the same time')
|
26
|
+
end
|
27
|
+
|
28
|
+
config.clear_local unless flags[:global]
|
29
|
+
config.clear_global if flags[:global] || flags[:all]
|
19
30
|
end
|
20
31
|
end
|
21
32
|
end
|
@@ -5,15 +5,15 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Current < BaseCommand
|
8
|
-
def self.
|
9
|
-
'current asana[:<project-gid>[/<task-gid>]]'
|
8
|
+
def self.usage
|
9
|
+
'abt current asana[:<project-gid>[/<task-gid>]]'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
13
|
'Get or set project and or task for current git repository'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def perform
|
17
17
|
require_project!
|
18
18
|
|
19
19
|
if same_args_as_config? || !config.local_available?
|
@@ -5,15 +5,15 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Finalize < BaseCommand
|
8
|
-
def self.
|
9
|
-
'finalize asana[:<project-gid>/<task-gid>]'
|
8
|
+
def self.usage
|
9
|
+
'abt finalize asana[:<project-gid>/<task-gid>]'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
13
|
'Move current/specified task to section (column) for finalized tasks'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def perform
|
17
17
|
unless config.local_available?
|
18
18
|
cli.abort 'This is a no-op for tasks outside the current project'
|
19
19
|
end
|
@@ -5,15 +5,15 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class HarvestTimeEntryData < BaseCommand
|
8
|
-
def self.
|
9
|
-
'harvest-time-entry-data asana[:<project-gid>/<task-gid>]'
|
8
|
+
def self.usage
|
9
|
+
'abt harvest-time-entry-data asana[:<project-gid>/<task-gid>]'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
13
|
'Print Harvest time entry data for Asana task as json. Used by harvest start script.'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def perform
|
17
17
|
require_task!
|
18
18
|
ensure_current_is_valid!
|
19
19
|
|
@@ -5,8 +5,8 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Init < BaseCommand
|
8
|
-
def self.
|
9
|
-
'init asana'
|
8
|
+
def self.usage
|
9
|
+
'abt init asana'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
@@ -18,7 +18,7 @@ module Abt
|
|
18
18
|
@cli = cli
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def perform
|
22
22
|
cli.abort 'Must be run inside a git repository' unless config.local_available?
|
23
23
|
|
24
24
|
projects # Load projects up front to make it obvious that searches are instant
|
@@ -35,14 +35,14 @@ module Abt
|
|
35
35
|
cli.warn 'Select a project'
|
36
36
|
|
37
37
|
loop do
|
38
|
-
matches = matches_for_string cli.prompt('Enter search')
|
38
|
+
matches = matches_for_string cli.prompt.text('Enter search')
|
39
39
|
if matches.empty?
|
40
40
|
cli.warn 'No matches'
|
41
41
|
next
|
42
42
|
end
|
43
43
|
|
44
44
|
cli.warn 'Showing the 10 first matches' if matches.size > 10
|
45
|
-
choice = cli.
|
45
|
+
choice = cli.prompt.choice 'Select a project', matches[0...10], true
|
46
46
|
break choice unless choice.nil?
|
47
47
|
end
|
48
48
|
end
|
@@ -5,15 +5,21 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Pick < BaseCommand
|
8
|
-
def self.
|
9
|
-
'pick asana[:<project-gid>]'
|
8
|
+
def self.usage
|
9
|
+
'abt pick asana[:<project-gid>]'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
13
|
'Pick task for current git repository'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def self.flags
|
17
|
+
[
|
18
|
+
['-d', '--dry-run', 'Keep existing configuration']
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def perform
|
17
23
|
cli.abort 'Must be run inside a git repository' unless config.local_available?
|
18
24
|
require_project!
|
19
25
|
|
@@ -21,10 +27,12 @@ module Abt
|
|
21
27
|
|
22
28
|
task = select_task
|
23
29
|
|
24
|
-
config.project_gid = project_gid # We might have gotten the project ID as an argument
|
25
|
-
config.task_gid = task['gid']
|
26
|
-
|
27
30
|
print_task(project, task)
|
31
|
+
|
32
|
+
return if flags[:"dry-run"]
|
33
|
+
|
34
|
+
config.project_gid = project_gid # We might have gotten the project ID from a path
|
35
|
+
config.task_gid = task['gid']
|
28
36
|
end
|
29
37
|
|
30
38
|
private
|
@@ -35,7 +43,7 @@ module Abt
|
|
35
43
|
|
36
44
|
def select_task
|
37
45
|
loop do
|
38
|
-
section = cli.
|
46
|
+
section = cli.prompt.choice 'Which section?', sections
|
39
47
|
cli.warn 'Fetching tasks...'
|
40
48
|
tasks = tasks_in_section(section)
|
41
49
|
|
@@ -44,7 +52,7 @@ module Abt
|
|
44
52
|
next
|
45
53
|
end
|
46
54
|
|
47
|
-
task = cli.
|
55
|
+
task = cli.prompt.choice 'Select a task', tasks, true
|
48
56
|
return task if task
|
49
57
|
end
|
50
58
|
end
|
@@ -5,15 +5,15 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Projects < BaseCommand
|
8
|
-
def self.
|
9
|
-
'projects asana'
|
8
|
+
def self.usage
|
9
|
+
'abt projects asana'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
13
|
'List all available projects - useful for piping into grep etc.'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def perform
|
17
17
|
projects.map do |project|
|
18
18
|
print_project(project)
|
19
19
|
end
|
@@ -5,21 +5,21 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Share < BaseCommand
|
8
|
-
def self.
|
9
|
-
'share asana[:<project-gid>[/<task-gid>]]'
|
8
|
+
def self.usage
|
9
|
+
'abt share asana[:<project-gid>[/<task-gid>]]'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
13
|
'Print project/task config string'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def perform
|
17
17
|
require_project!
|
18
18
|
|
19
19
|
if task_gid.nil?
|
20
|
-
cli.
|
20
|
+
cli.print_ari('asana', project_gid)
|
21
21
|
else
|
22
|
-
cli.
|
22
|
+
cli.print_ari('asana', "#{project_gid}/#{task_gid}")
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -5,15 +5,21 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Start < BaseCommand
|
8
|
-
def self.
|
9
|
-
'start asana[:<project-gid>/<task-gid>]'
|
8
|
+
def self.usage
|
9
|
+
'abt start asana[:<project-gid>/<task-gid>]'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
'
|
13
|
+
'Move current or specified task to WIP section (column) and assign it to you'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def self.flags
|
17
|
+
[
|
18
|
+
['-s', '--set', 'Set specified task as current']
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
def perform
|
17
23
|
require_task!
|
18
24
|
|
19
25
|
maybe_override_current_task
|
@@ -25,12 +31,12 @@ module Abt
|
|
25
31
|
private
|
26
32
|
|
27
33
|
def maybe_override_current_task
|
28
|
-
return
|
34
|
+
return unless flags[:set]
|
35
|
+
return if path.nil?
|
29
36
|
return if same_args_as_config?
|
30
37
|
return unless config.local_available?
|
31
38
|
|
32
|
-
|
33
|
-
Current.new(arg_str: arg_str, cli: cli).call if should_override
|
39
|
+
Current.new(path: path, cli: cli).call
|
34
40
|
end
|
35
41
|
|
36
42
|
def update_assignee_if_needed
|
@@ -41,7 +47,7 @@ module Abt
|
|
41
47
|
update_assignee
|
42
48
|
elsif current_assignee['gid'] == current_user['gid']
|
43
49
|
cli.warn 'You are already assigned to this task'
|
44
|
-
elsif cli.
|
50
|
+
elsif cli.prompt.boolean "Task is assigned to: #{current_assignee['name']}, take over?"
|
45
51
|
cli.warn "Reassigning task to user: #{current_user['name']}"
|
46
52
|
update_assignee
|
47
53
|
end
|
@@ -5,15 +5,15 @@ module Abt
|
|
5
5
|
module Asana
|
6
6
|
module Commands
|
7
7
|
class Tasks < BaseCommand
|
8
|
-
def self.
|
9
|
-
'tasks asana'
|
8
|
+
def self.usage
|
9
|
+
'abt tasks asana'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
13
|
'List available tasks on project - useful for piping into grep etc.'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def perform
|
17
17
|
require_project!
|
18
18
|
|
19
19
|
tasks.each do |task|
|
@@ -49,7 +49,7 @@ module Abt
|
|
49
49
|
def project_gid=(value)
|
50
50
|
return if project_gid == value
|
51
51
|
|
52
|
-
clear_local
|
52
|
+
clear_local(verbose: false)
|
53
53
|
git['projectGid'] = value unless value.nil?
|
54
54
|
end
|
55
55
|
|
@@ -57,26 +57,18 @@ module Abt
|
|
57
57
|
git['taskGid'] = value
|
58
58
|
end
|
59
59
|
|
60
|
-
def clear_local
|
61
|
-
|
62
|
-
|
63
|
-
git['projectGid'] = nil
|
64
|
-
git['taskGid'] = nil
|
65
|
-
git['wipSectionGid'] = nil
|
66
|
-
git['finalizedSectionGid'] = nil
|
60
|
+
def clear_local(verbose: true)
|
61
|
+
git.clear(output: verbose ? cli.err_output : nil)
|
67
62
|
end
|
68
63
|
|
69
|
-
def clear_global
|
70
|
-
git.global.
|
71
|
-
cli.puts 'Deleting configuration: ' + key
|
72
|
-
git.global[key] = nil
|
73
|
-
end
|
64
|
+
def clear_global(verbose: true)
|
65
|
+
git.global.clear(output: verbose ? cli.err_output : nil)
|
74
66
|
end
|
75
67
|
|
76
68
|
def access_token
|
77
69
|
return git.global['accessToken'] unless git.global['accessToken'].nil?
|
78
70
|
|
79
|
-
git.global['accessToken'] = cli.prompt([
|
71
|
+
git.global['accessToken'] = cli.prompt.text([
|
80
72
|
'Please provide your personal access token for Asana.',
|
81
73
|
'If you don\'t have one, create one here: https://app.asana.com/0/developer-console',
|
82
74
|
'',
|
@@ -103,7 +95,7 @@ module Abt
|
|
103
95
|
def prompt_section(message)
|
104
96
|
cli.warn 'Fetching sections...'
|
105
97
|
sections = api.get_paged("projects/#{project_gid}/sections")
|
106
|
-
cli.
|
98
|
+
cli.prompt.choice(message, sections)
|
107
99
|
end
|
108
100
|
|
109
101
|
def prompt_workspace
|
@@ -115,7 +107,7 @@ module Abt
|
|
115
107
|
workspace = workspaces.first
|
116
108
|
cli.warn "Selected Asana workspace #{workspace['name']}"
|
117
109
|
else
|
118
|
-
workspace = cli.
|
110
|
+
workspace = cli.prompt.choice('Select Asana workspace', workspaces)
|
119
111
|
end
|
120
112
|
|
121
113
|
git.global['workspaceGid'] = workspace['gid']
|
@@ -3,19 +3,18 @@
|
|
3
3
|
module Abt
|
4
4
|
module Providers
|
5
5
|
module Devops
|
6
|
-
class BaseCommand
|
7
|
-
attr_reader :
|
6
|
+
class BaseCommand < Abt::Cli::BaseCommand
|
7
|
+
attr_reader :organization_name, :project_name, :board_id, :work_item_id, :config
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
|
9
|
+
def initialize(path:, cli:, **)
|
10
|
+
super
|
11
11
|
|
12
12
|
@config = Configuration.new(cli: cli)
|
13
|
-
@cli = cli
|
14
13
|
|
15
|
-
if
|
16
|
-
|
14
|
+
if path.nil?
|
15
|
+
use_current_path
|
17
16
|
else
|
18
|
-
|
17
|
+
use_path(path)
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
@@ -55,28 +54,28 @@ module Abt
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def print_board(organization_name, project_name, board)
|
58
|
-
|
57
|
+
path = "#{organization_name}/#{project_name}/#{board['id']}"
|
59
58
|
|
60
|
-
cli.
|
59
|
+
cli.print_ari('devops', path, board['name'])
|
61
60
|
# cli.warn board['url'] if board.key?('url') && cli.output.isatty # TODO: Web URL
|
62
61
|
end
|
63
62
|
|
64
63
|
def print_work_item(organization, project, board, work_item)
|
65
|
-
|
64
|
+
path = "#{organization}/#{project}/#{board['id']}/#{work_item['id']}"
|
66
65
|
|
67
|
-
cli.
|
66
|
+
cli.print_ari('devops', path, work_item['name'])
|
68
67
|
cli.warn work_item['url'] if work_item.key?('url') && cli.output.isatty
|
69
68
|
end
|
70
69
|
|
71
|
-
def
|
70
|
+
def use_current_path
|
72
71
|
@organization_name = config.organization_name
|
73
72
|
@project_name = config.project_name
|
74
73
|
@board_id = config.board_id
|
75
74
|
@work_item_id = config.work_item_id
|
76
75
|
end
|
77
76
|
|
78
|
-
def
|
79
|
-
args =
|
77
|
+
def use_path(path)
|
78
|
+
args = path.to_s.split('/')
|
80
79
|
|
81
80
|
if args.length < 3
|
82
81
|
cli.abort 'Argument format is <organization>/<project>/<board-id>[/<work-item-id>]'
|
@@ -5,16 +5,18 @@ module Abt
|
|
5
5
|
module Devops
|
6
6
|
module Commands
|
7
7
|
class Boards < BaseCommand
|
8
|
-
def self.
|
9
|
-
'boards devops'
|
8
|
+
def self.usage
|
9
|
+
'abt boards devops'
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
13
|
'List all boards - useful for piping into grep etc'
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
16
|
+
def perform
|
17
|
+
if organization_name.nil?
|
18
|
+
cli.abort 'No organization selected. Did you initialize DevOps?'
|
19
|
+
end
|
18
20
|
cli.abort 'No project selected. Did you initialize DevOps?' if project_name.nil?
|
19
21
|
|
20
22
|
boards.map do |board|
|