abt-cli 0.0.21 → 0.0.22
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -22,28 +22,26 @@ module Abt
|
|
22
22
|
def require_project!
|
23
23
|
return if project_id
|
24
24
|
|
25
|
-
abort
|
25
|
+
abort("No current/specified project. Did you initialize Harvest?")
|
26
26
|
end
|
27
27
|
|
28
28
|
def require_task!
|
29
|
-
unless project_id
|
30
|
-
abort 'No current/specified project. Did you initialize Harvest and pick a task?'
|
31
|
-
end
|
29
|
+
abort("No current/specified project. Did you initialize Harvest and pick a task?") unless project_id
|
32
30
|
|
33
|
-
abort
|
31
|
+
abort("No current/specified task. Did you pick a Harvest task?") if task_id.nil?
|
34
32
|
end
|
35
33
|
|
36
34
|
def print_project(project)
|
37
35
|
cli.print_ari(
|
38
|
-
|
39
|
-
project[
|
36
|
+
"harvest",
|
37
|
+
project["id"],
|
40
38
|
"#{project['client']['name']} > #{project['name']}"
|
41
39
|
)
|
42
40
|
end
|
43
41
|
|
44
42
|
def print_task(project, task)
|
45
43
|
cli.print_ari(
|
46
|
-
|
44
|
+
"harvest",
|
47
45
|
"#{project['id']}/#{task['id']}",
|
48
46
|
"#{project['name']} > #{task['name']}"
|
49
47
|
)
|
@@ -6,29 +6,28 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Clear < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt clear harvest"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Clear harvest configuration"
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.flags
|
17
17
|
[
|
18
|
-
[
|
19
|
-
|
18
|
+
["-g", "--global",
|
19
|
+
"Clear global instead of local harvest configuration (credentials etc.)"],
|
20
|
+
["-a", "--all", "Clear all harvest configuration"]
|
20
21
|
]
|
21
22
|
end
|
22
23
|
|
23
24
|
def perform
|
24
|
-
if flags[:global] && flags[:all]
|
25
|
-
abort('Flags --global and --all cannot be used at the same time')
|
26
|
-
end
|
25
|
+
abort("Flags --global and --all cannot be used at the same time") if flags[:global] && flags[:all]
|
27
26
|
|
28
27
|
config.clear_local unless flags[:global]
|
29
28
|
config.clear_global if flags[:global] || flags[:all]
|
30
29
|
|
31
|
-
warn
|
30
|
+
warn("Configuration cleared")
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
@@ -6,22 +6,22 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Current < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt current harvest[:<project-id>[/<task-id>]]"
|
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
16
|
def perform
|
17
|
-
abort
|
17
|
+
abort("Must be run inside a git repository") unless config.local_available?
|
18
18
|
|
19
19
|
require_project!
|
20
20
|
ensure_valid_configuration!
|
21
21
|
|
22
22
|
if path != config.path
|
23
23
|
config.path = path
|
24
|
-
warn
|
24
|
+
warn("Configuration updated")
|
25
25
|
end
|
26
26
|
|
27
27
|
print_configuration
|
@@ -38,36 +38,36 @@ module Abt
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def ensure_valid_configuration!
|
41
|
-
abort
|
42
|
-
abort
|
41
|
+
abort("Invalid project: #{project_id}") if project.nil?
|
42
|
+
abort("Invalid task: #{task_id}") if task_id && task.nil?
|
43
43
|
end
|
44
44
|
|
45
45
|
def project
|
46
|
-
return @project if instance_variable_defined?
|
46
|
+
return @project if instance_variable_defined?(:@project)
|
47
47
|
|
48
48
|
@project = if project_assignment
|
49
|
-
project_assignment[
|
49
|
+
project_assignment["project"].merge("client" => project_assignment["client"])
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
def task
|
54
|
-
return @task if instance_variable_defined?
|
54
|
+
return @task if instance_variable_defined?(:@task)
|
55
55
|
|
56
56
|
@task = if project_assignment
|
57
|
-
project_assignment[
|
58
|
-
task[
|
57
|
+
project_assignment["task_assignments"].map { |ta| ta["task"] }.find do |task|
|
58
|
+
task["id"].to_s == task_id
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
63
|
def project_assignment
|
64
64
|
@project_assignment ||= begin
|
65
|
-
project_assignments.find { |pa| pa[
|
65
|
+
project_assignments.find { |pa| pa["project"]["id"].to_s == project_id }
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
69
|
def project_assignments
|
70
|
-
@project_assignments ||= api.get_paged(
|
70
|
+
@project_assignments ||= api.get_paged("users/me/project_assignments")
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
@@ -6,74 +6,46 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Init < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt init harvest"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Pick Harvest project for current git repository"
|
14
14
|
end
|
15
15
|
|
16
16
|
def perform
|
17
|
-
abort
|
17
|
+
abort("Must be run inside a git repository") unless config.local_available?
|
18
18
|
|
19
19
|
projects # Load projects up front to make it obvious that searches are instant
|
20
|
-
project =
|
20
|
+
project = cli.prompt.search("Select a project", searchable_projects)["project"]
|
21
21
|
|
22
|
-
config.path = Path.from_ids(project[
|
22
|
+
config.path = Path.from_ids(project["id"])
|
23
23
|
|
24
24
|
print_project(project)
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
28
28
|
|
29
|
-
def find_search_result
|
30
|
-
warn 'Select a project'
|
31
|
-
|
32
|
-
loop do
|
33
|
-
matches = matches_for_string cli.prompt.text('Enter search')
|
34
|
-
if matches.empty?
|
35
|
-
warn 'No matches'
|
36
|
-
next
|
37
|
-
end
|
38
|
-
|
39
|
-
warn 'Showing the 10 first matches' if matches.size > 10
|
40
|
-
choice = cli.prompt.choice 'Select a project', matches[0...10], true
|
41
|
-
break choice['project'] unless choice.nil?
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def matches_for_string(string)
|
46
|
-
search_string = sanitize_string(string)
|
47
|
-
|
48
|
-
searchable_projects.select do |project|
|
49
|
-
sanitize_string(project['name']).include?(search_string)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def sanitize_string(string)
|
54
|
-
string.downcase.gsub(/[^\w]/, '')
|
55
|
-
end
|
56
|
-
|
57
29
|
def searchable_projects
|
58
30
|
@searchable_projects ||= projects.map do |project|
|
59
31
|
{
|
60
|
-
|
61
|
-
|
32
|
+
"name" => "#{project['client']['name']} > #{project['name']}",
|
33
|
+
"project" => project
|
62
34
|
}
|
63
35
|
end
|
64
36
|
end
|
65
37
|
|
66
38
|
def projects
|
67
39
|
@projects ||= begin
|
68
|
-
warn
|
40
|
+
warn("Fetching projects...")
|
69
41
|
project_assignments.map do |project_assignment|
|
70
|
-
project_assignment[
|
42
|
+
project_assignment["project"].merge("client" => project_assignment["client"])
|
71
43
|
end
|
72
44
|
end
|
73
45
|
end
|
74
46
|
|
75
47
|
def project_assignments
|
76
|
-
@project_assignments ||= api.get_paged(
|
48
|
+
@project_assignments ||= api.get_paged("users/me/project_assignments")
|
77
49
|
end
|
78
50
|
end
|
79
51
|
end
|
@@ -6,51 +6,51 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Pick < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt pick harvest[:<project-id>]"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Pick task for current git repository"
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.flags
|
17
17
|
[
|
18
|
-
[
|
18
|
+
["-d", "--dry-run", "Keep existing configuration"]
|
19
19
|
]
|
20
20
|
end
|
21
21
|
|
22
22
|
def perform
|
23
|
-
abort
|
23
|
+
abort("Must be run inside a git repository") unless config.local_available?
|
24
24
|
require_project!
|
25
25
|
|
26
|
-
warn
|
27
|
-
task = cli.prompt.choice
|
26
|
+
warn(project["name"])
|
27
|
+
task = cli.prompt.choice("Select a task", tasks)
|
28
28
|
|
29
29
|
print_task(project, task)
|
30
30
|
|
31
31
|
return if flags[:"dry-run"]
|
32
32
|
|
33
|
-
config.path = Path.from_ids(project_id, task[
|
33
|
+
config.path = Path.from_ids(project_id, task["id"])
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
38
|
def project
|
39
|
-
project_assignment[
|
39
|
+
project_assignment["project"]
|
40
40
|
end
|
41
41
|
|
42
42
|
def tasks
|
43
|
-
@tasks ||= project_assignment[
|
43
|
+
@tasks ||= project_assignment["task_assignments"].map { |ta| ta["task"] }
|
44
44
|
end
|
45
45
|
|
46
46
|
def project_assignment
|
47
47
|
@project_assignment ||= begin
|
48
|
-
project_assignments.find { |pa| pa[
|
48
|
+
project_assignments.find { |pa| pa["project"]["id"].to_s == project_id }
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
def project_assignments
|
53
|
-
@project_assignments ||= api.get_paged(
|
53
|
+
@project_assignments ||= api.get_paged("users/me/project_assignments")
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
@@ -6,11 +6,11 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Projects < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt projects harvest"
|
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
16
|
def perform
|
@@ -23,15 +23,15 @@ module Abt
|
|
23
23
|
|
24
24
|
def projects
|
25
25
|
@projects ||= begin
|
26
|
-
warn
|
26
|
+
warn("Fetching projects...")
|
27
27
|
project_assignments.map do |project_assignment|
|
28
|
-
project_assignment[
|
28
|
+
project_assignment["project"].merge("client" => project_assignment["client"])
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
def project_assignments
|
34
|
-
@project_assignments ||= api.get_paged(
|
34
|
+
@project_assignments ||= api.get_paged("users/me/project_assignments")
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -6,18 +6,18 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Share < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt share harvest[:<project-id>[/<task-id>]]"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Print project/task ARI"
|
14
14
|
end
|
15
15
|
|
16
16
|
def perform
|
17
|
-
if path !=
|
18
|
-
cli.print_ari(
|
17
|
+
if path != ""
|
18
|
+
cli.print_ari("harvest", path)
|
19
19
|
elsif cli.output.isatty
|
20
|
-
warn
|
20
|
+
warn("No configuration for project. Did you initialize Harvest?")
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "track"
|
4
4
|
|
5
5
|
module Abt
|
6
6
|
module Providers
|
@@ -8,11 +8,13 @@ module Abt
|
|
8
8
|
module Commands
|
9
9
|
class Start < Track
|
10
10
|
def self.usage
|
11
|
-
|
11
|
+
"abt start harvest[:<project-id>/<task-id>] [options]"
|
12
12
|
end
|
13
13
|
|
14
14
|
def self.description
|
15
|
-
|
15
|
+
<<~TXT
|
16
|
+
Alias for: `abt track harvest`. Meant to used in combination with other ARIs, e.g. `abt start harvest asana`
|
17
|
+
TXT
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
@@ -6,19 +6,19 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Stop < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt stop harvest"
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.description
|
13
|
-
|
13
|
+
"Stop running harvest tracker"
|
14
14
|
end
|
15
15
|
|
16
16
|
def perform
|
17
|
-
abort
|
17
|
+
abort("No running time entry") if time_entry.nil?
|
18
18
|
|
19
19
|
stop_time_entry
|
20
20
|
|
21
|
-
warn
|
21
|
+
warn("Harvest time entry stopped")
|
22
22
|
print_task(project, task)
|
23
23
|
end
|
24
24
|
|
@@ -27,28 +27,28 @@ module Abt
|
|
27
27
|
def stop_time_entry
|
28
28
|
api.patch("time_entries/#{time_entry['id']}/stop")
|
29
29
|
rescue Abt::HttpError::HttpError => e
|
30
|
-
warn
|
31
|
-
abort
|
30
|
+
warn(e)
|
31
|
+
abort("Unable to stop time entry")
|
32
32
|
end
|
33
33
|
|
34
34
|
def project
|
35
|
-
time_entry[
|
35
|
+
time_entry["project"]
|
36
36
|
end
|
37
37
|
|
38
38
|
def task
|
39
|
-
time_entry[
|
39
|
+
time_entry["task"]
|
40
40
|
end
|
41
41
|
|
42
42
|
def time_entry
|
43
43
|
@time_entry ||= begin
|
44
44
|
api.get_paged(
|
45
|
-
|
45
|
+
"time_entries",
|
46
46
|
is_running: true,
|
47
47
|
user_id: config.user_id
|
48
48
|
).first
|
49
|
-
rescue Abt::HttpError::HttpError => e
|
50
|
-
warn
|
51
|
-
abort
|
49
|
+
rescue Abt::HttpError::HttpError => e
|
50
|
+
warn(e)
|
51
|
+
abort("Unable to fetch running time entry")
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end
|
@@ -6,11 +6,11 @@ module Abt
|
|
6
6
|
module Commands
|
7
7
|
class Tasks < BaseCommand
|
8
8
|
def self.usage
|
9
|
-
|
9
|
+
"abt tasks harvest"
|
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
16
|
def perform
|
@@ -24,24 +24,24 @@ module Abt
|
|
24
24
|
private
|
25
25
|
|
26
26
|
def project
|
27
|
-
project_assignment[
|
27
|
+
project_assignment["project"]
|
28
28
|
end
|
29
29
|
|
30
30
|
def tasks
|
31
31
|
@tasks ||= begin
|
32
|
-
warn
|
33
|
-
project_assignment[
|
32
|
+
warn("Fetching tasks...")
|
33
|
+
project_assignment["task_assignments"].map { |ta| ta["task"] }
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
37
|
def project_assignment
|
38
38
|
@project_assignment ||= begin
|
39
|
-
project_assignments.find { |pa| pa[
|
39
|
+
project_assignments.find { |pa| pa["project"]["id"].to_s == project_id }
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
def project_assignments
|
44
|
-
@project_assignments ||= api.get_paged(
|
44
|
+
@project_assignments ||= api.get_paged("users/me/project_assignments")
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|