abt-cli 0.0.3 → 0.0.8

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/bin/abt +2 -0
  3. data/lib/abt/cli.rb +16 -7
  4. data/lib/abt/cli/dialogs.rb +18 -2
  5. data/lib/abt/cli/io.rb +8 -6
  6. data/lib/abt/docs.rb +16 -5
  7. data/lib/abt/docs/cli.rb +1 -1
  8. data/lib/abt/docs/markdown.rb +1 -1
  9. data/lib/abt/git_config.rb +55 -49
  10. data/lib/abt/providers/asana/api.rb +1 -1
  11. data/lib/abt/providers/asana/base_command.rb +9 -4
  12. data/lib/abt/providers/asana/commands/current.rb +10 -4
  13. data/lib/abt/providers/asana/commands/finalize.rb +71 -0
  14. data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +2 -2
  15. data/lib/abt/providers/asana/commands/init.rb +10 -3
  16. data/lib/abt/providers/asana/commands/{pick_task.rb → pick.rb} +13 -6
  17. data/lib/abt/providers/asana/commands/projects.rb +9 -2
  18. data/lib/abt/providers/asana/commands/share.rb +29 -0
  19. data/lib/abt/providers/asana/commands/start.rb +51 -6
  20. data/lib/abt/providers/asana/commands/tasks.rb +4 -1
  21. data/lib/abt/providers/asana/configuration.rb +54 -34
  22. data/lib/abt/providers/harvest.rb +9 -51
  23. data/lib/abt/providers/harvest/api.rb +62 -0
  24. data/lib/abt/providers/harvest/base_command.rb +12 -16
  25. data/lib/abt/providers/harvest/commands/clear.rb +24 -0
  26. data/lib/abt/providers/harvest/commands/clear_global.rb +24 -0
  27. data/lib/abt/providers/harvest/commands/current.rb +83 -0
  28. data/lib/abt/providers/harvest/commands/init.rb +83 -0
  29. data/lib/abt/providers/harvest/commands/pick.rb +51 -0
  30. data/lib/abt/providers/harvest/commands/projects.rb +40 -0
  31. data/lib/abt/providers/harvest/commands/share.rb +29 -0
  32. data/lib/abt/providers/harvest/commands/start.rb +58 -0
  33. data/lib/abt/providers/harvest/commands/stop.rb +58 -0
  34. data/lib/abt/providers/harvest/commands/tasks.rb +45 -0
  35. data/lib/abt/providers/harvest/commands/track.rb +70 -0
  36. data/lib/abt/providers/harvest/configuration.rb +91 -0
  37. data/lib/abt/version.rb +1 -1
  38. metadata +18 -14
  39. data/lib/abt/harvest_client.rb +0 -58
  40. data/lib/abt/providers/asana/commands/move.rb +0 -56
  41. data/lib/abt/providers/harvest/clear.rb +0 -24
  42. data/lib/abt/providers/harvest/clear_global.rb +0 -24
  43. data/lib/abt/providers/harvest/current.rb +0 -79
  44. data/lib/abt/providers/harvest/init.rb +0 -61
  45. data/lib/abt/providers/harvest/pick_task.rb +0 -45
  46. data/lib/abt/providers/harvest/projects.rb +0 -29
  47. data/lib/abt/providers/harvest/start.rb +0 -58
  48. data/lib/abt/providers/harvest/stop.rb +0 -51
  49. data/lib/abt/providers/harvest/tasks.rb +0 -36
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- module Asana
6
- module Commands
7
- class Move < BaseCommand
8
- def self.command
9
- 'move asana[:<project-gid>/<task-gid>]'
10
- end
11
-
12
- def self.description
13
- 'Move current or specified task to another section (column)'
14
- end
15
-
16
- def call
17
- print_task(project, task)
18
-
19
- move_task
20
-
21
- cli.warn "Asana task moved to #{section['name']}"
22
- rescue Abt::HttpError::HttpError => e
23
- cli.warn e
24
- cli.abort 'Unable to move asana task'
25
- end
26
-
27
- private
28
-
29
- def task
30
- @task ||= api.get("tasks/#{task_gid}")
31
- end
32
-
33
- def move_task
34
- body = { data: { task: task_gid } }
35
- body_json = Oj.dump(body, mode: :json)
36
- api.post("sections/#{section['gid']}/addTask", body_json)
37
- end
38
-
39
- def section
40
- @section ||= cli.prompt_choice 'Move asana task to?', sections
41
- end
42
-
43
- def project
44
- @project ||= api.get("projects/#{project_gid}")
45
- end
46
-
47
- def sections
48
- api.get_paged("projects/#{project_gid}/sections")
49
- rescue Abt::HttpError::HttpError
50
- []
51
- end
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class Clear
7
- def self.command
8
- 'clear harvest'
9
- end
10
-
11
- def self.description
12
- 'Clear project/task for current git repository'
13
- end
14
-
15
- def initialize(**); end
16
-
17
- def call
18
- warn 'Clearing Harvest project configuration'
19
- Harvest.clear
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class ClearGlobal
7
- def self.command
8
- 'clear-global harvest'
9
- end
10
-
11
- def self.description
12
- 'Clear all global configuration'
13
- end
14
-
15
- def initialize(**); end
16
-
17
- def call
18
- warn 'Clearing Harvest project configuration'
19
- Harvest.clear_global
20
- end
21
- end
22
- end
23
- end
24
- end
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class Current < BaseCommand
7
- def self.command
8
- 'current harvest[:<project-id>[/<task-id>]]'
9
- end
10
-
11
- def self.description
12
- 'Get or set project and or task for current git repository'
13
- end
14
-
15
- def call
16
- if arg_str.nil?
17
- show_current_configuration
18
- else
19
- warn 'Updating configuration'
20
- update_configuration
21
- end
22
- end
23
-
24
- private
25
-
26
- def show_current_configuration
27
- if project_id.nil?
28
- warn 'No project selected'
29
- elsif task_id.nil?
30
- print_project(project)
31
- else
32
- print_task(project, task)
33
- end
34
- end
35
-
36
- def update_configuration
37
- ensure_project_is_valid!
38
- remember_project_id(project_id)
39
-
40
- if task_id.nil?
41
- print_project(project)
42
- remember_task_id(nil)
43
- else
44
- ensure_task_is_valid!
45
- remember_task_id(task_id)
46
-
47
- print_task(project, task)
48
- end
49
- end
50
-
51
- def ensure_project_is_valid!
52
- abort "Invalid project: #{project_id}" if project.nil?
53
- end
54
-
55
- def ensure_task_is_valid!
56
- abort "Invalid task: #{task_id}" if task.nil?
57
- end
58
-
59
- def project
60
- @project ||= Harvest.client.get("projects/#{project_id}")
61
- end
62
-
63
- def task
64
- project_task_assignments
65
- .map { |assignment| assignment['task'] }
66
- .find { |task| task['id'].to_s == task_id }
67
- end
68
-
69
- def project_task_assignments
70
- @project_task_assignments ||= begin
71
- Harvest.client.get_paged("projects/#{project_id}/task_assignments", is_active: true)
72
- rescue Abt::HttpError::HttpError # rubocop:disable Layout/RescueEnsureAlignment
73
- []
74
- end
75
- end
76
- end
77
- end
78
- end
79
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class Init < BaseCommand
7
- def self.command
8
- 'init harvest'
9
- end
10
-
11
- def self.description
12
- 'Pick Harvest project for current git repository'
13
- end
14
-
15
- def call
16
- warn 'Loading projects'
17
-
18
- projects # Load projects up front to make it obvious that searches are instant
19
- project = find_search_result
20
-
21
- remember_project_id(project['id'])
22
- remember_task_id(nil)
23
-
24
- print_project(project)
25
- end
26
-
27
- private
28
-
29
- def find_search_result
30
- loop do
31
- matches = matches_for_string cli.prompt('Enter search')
32
- if matches.empty?
33
- warn 'No matches'
34
- next
35
- end
36
-
37
- warn 'Showing the 10 first matches' if matches.size > 10
38
- choice = cli.prompt_choice 'Select a project', matches[0...10], true
39
- break choice unless choice.nil?
40
- end
41
- end
42
-
43
- def matches_for_string(string)
44
- search_string = sanitize_string(string)
45
-
46
- projects.select do |project|
47
- sanitize_string(project['name']).include?(search_string)
48
- end
49
- end
50
-
51
- def sanitize_string(string)
52
- string.downcase.gsub(/[^\w]/, '')
53
- end
54
-
55
- def projects
56
- @projects ||= Harvest.client.get_paged('projects')
57
- end
58
- end
59
- end
60
- end
61
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class PickTask < BaseCommand
7
- def self.command
8
- 'pick-task harvest[:<project-id>]'
9
- end
10
-
11
- def self.description
12
- 'Pick task for current git repository'
13
- end
14
-
15
- def call
16
- warn project['name']
17
- task = cli.prompt_choice 'Select a task', tasks
18
-
19
- remember_project_id(project_id) # We might have gotten the project ID as an argument
20
- remember_task_id(task['id'])
21
-
22
- print_task(project, task)
23
- end
24
-
25
- private
26
-
27
- def project
28
- @project ||= Harvest.client.get("projects/#{project_id}")
29
- end
30
-
31
- def tasks
32
- project_task_assignments.map { |assignment| assignment['task'] }
33
- end
34
-
35
- def project_task_assignments
36
- @project_task_assignments ||= begin
37
- Harvest.client.get_paged("projects/#{project_id}/task_assignments", is_active: true)
38
- rescue Abt::HttpError::HttpError # rubocop:disable Layout/RescueEnsureAlignment
39
- []
40
- end
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class Projects < BaseCommand
7
- def self.command
8
- 'projects harvest'
9
- end
10
-
11
- def self.description
12
- 'List all available projects - useful for piping into grep etc.'
13
- end
14
-
15
- def call
16
- projects.map do |project|
17
- print_project(project)
18
- end
19
- end
20
-
21
- private
22
-
23
- def projects
24
- @projects ||= Harvest.client.get_paged('projects', is_active: true)
25
- end
26
- end
27
- end
28
- end
29
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class Start < BaseCommand
7
- def self.command
8
- 'start harvest[:<project-id>/<task-id>]'
9
- end
10
-
11
- def self.description
12
- 'Start tracker for current or specified task. Add a relevant provider to link the time entry: E.g. `abt start harvest asana`' # rubocop:disable Layout/LineLength
13
- end
14
-
15
- def call
16
- Current.new(arg_str: arg_str, cli: cli).call unless arg_str.nil?
17
-
18
- abort('No task selected') if task_id.nil?
19
-
20
- create_time_entry
21
-
22
- warn 'Tracker successfully started'
23
- rescue Abt::HttpError::HttpError => e
24
- warn e
25
- abort 'Unable to start tracker'
26
- end
27
-
28
- private
29
-
30
- def create_time_entry
31
- body = Oj.dump({
32
- project_id: Abt::GitConfig.local('abt.harvest.projectId'),
33
- task_id: Abt::GitConfig.local('abt.harvest.taskId'),
34
- user_id: Harvest.user_id,
35
- spent_date: Date.today.iso8601
36
- }.merge(external_link_data), mode: :json)
37
- Harvest.client.post('time_entries', body)
38
- end
39
-
40
- def external_link_data
41
- @external_link_data ||= begin
42
- arg_strs = cli.args.join(' ')
43
- lines = `#{$PROGRAM_NAME} harvest-time-entry-data #{arg_strs}`.split("\n")
44
-
45
- return {} if lines.empty?
46
-
47
- # TODO: Make user choose which reference to use by printing the urls
48
- if lines.length > 1
49
- abort 'Multiple providers had harvest reference data, only one is supported at a time'
50
- end
51
-
52
- Oj.load(lines.first)
53
- end
54
- end
55
- end
56
- end
57
- end
58
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class Stop < BaseCommand
7
- def self.command
8
- 'stop harvest'
9
- end
10
-
11
- def self.description
12
- 'Stop running harvest tracker'
13
- end
14
-
15
- def call
16
- abort 'No running time entry' if time_entry.nil?
17
-
18
- Harvest.client.patch("time_entries/#{time_entry['id']}/stop")
19
- warn 'Harvest time entry stopped'
20
- print_task(project, task)
21
- rescue Abt::HttpError::HttpError => e
22
- warn e
23
- abort 'Unable to stop time entry'
24
- end
25
-
26
- private
27
-
28
- def project
29
- time_entry['project']
30
- end
31
-
32
- def task
33
- time_entry['task']
34
- end
35
-
36
- def time_entry
37
- @time_entry ||= begin
38
- Harvest.client.get_paged(
39
- 'time_entries',
40
- is_running: true,
41
- user_id: Harvest.user_id
42
- ).first
43
- rescue Abt::HttpError::HttpError => e # rubocop:disable Layout/RescueEnsureAlignment
44
- warn e
45
- abort 'Unable to fetch running time entry'
46
- end
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Abt
4
- module Providers
5
- class Harvest
6
- class Tasks < BaseCommand
7
- def self.command
8
- 'tasks harvest'
9
- end
10
-
11
- def self.description
12
- 'List available tasks on project - useful for piping into grep etc.'
13
- end
14
-
15
- def call
16
- project_task_assignments.each do |a|
17
- project = a['project']
18
- task = a['task']
19
-
20
- print_task(project, task)
21
- end
22
- end
23
-
24
- private
25
-
26
- def project_task_assignments
27
- @project_task_assignments ||= begin
28
- Harvest.client.get_paged("projects/#{project_id}/task_assignments", is_active: true)
29
- rescue Abt::HttpError::HttpError # rubocop:disable Layout/RescueEnsureAlignment
30
- []
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end