abt-cli 0.0.2 → 0.0.7

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/bin/abt +4 -1
  3. data/lib/abt.rb +11 -0
  4. data/lib/abt/cli.rb +37 -32
  5. data/lib/abt/cli/dialogs.rb +18 -2
  6. data/lib/abt/cli/io.rb +23 -0
  7. data/lib/abt/docs.rb +57 -0
  8. data/lib/abt/{help → docs}/cli.rb +4 -4
  9. data/lib/abt/{help → docs}/markdown.rb +4 -4
  10. data/lib/abt/git_config.rb +55 -49
  11. data/lib/abt/helpers.rb +16 -0
  12. data/lib/abt/providers/asana.rb +9 -50
  13. data/lib/abt/providers/asana/api.rb +57 -0
  14. data/lib/abt/providers/asana/base_command.rb +14 -16
  15. data/lib/abt/providers/asana/commands/clear.rb +24 -0
  16. data/lib/abt/providers/asana/commands/clear_global.rb +24 -0
  17. data/lib/abt/providers/asana/commands/current.rb +77 -0
  18. data/lib/abt/providers/asana/commands/finalize.rb +71 -0
  19. data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +50 -0
  20. data/lib/abt/providers/asana/commands/init.rb +70 -0
  21. data/lib/abt/providers/asana/commands/pick.rb +55 -0
  22. data/lib/abt/providers/asana/commands/projects.rb +39 -0
  23. data/lib/abt/providers/asana/commands/share.rb +29 -0
  24. data/lib/abt/providers/asana/commands/start.rb +105 -0
  25. data/lib/abt/providers/asana/commands/tasks.rb +40 -0
  26. data/lib/abt/providers/asana/configuration.rb +125 -0
  27. data/lib/abt/providers/harvest.rb +9 -42
  28. data/lib/abt/providers/harvest/api.rb +62 -0
  29. data/lib/abt/providers/harvest/base_command.rb +12 -16
  30. data/lib/abt/providers/harvest/commands/clear.rb +24 -0
  31. data/lib/abt/providers/harvest/commands/clear_global.rb +24 -0
  32. data/lib/abt/providers/harvest/commands/current.rb +83 -0
  33. data/lib/abt/providers/harvest/commands/init.rb +83 -0
  34. data/lib/abt/providers/harvest/commands/pick.rb +51 -0
  35. data/lib/abt/providers/harvest/commands/projects.rb +40 -0
  36. data/lib/abt/providers/harvest/commands/share.rb +29 -0
  37. data/lib/abt/providers/harvest/commands/start.rb +101 -0
  38. data/lib/abt/providers/harvest/commands/stop.rb +58 -0
  39. data/lib/abt/providers/harvest/commands/tasks.rb +45 -0
  40. data/lib/abt/providers/harvest/configuration.rb +91 -0
  41. data/lib/abt/version.rb +1 -1
  42. metadata +32 -26
  43. data/lib/abt/asana_client.rb +0 -53
  44. data/lib/abt/harvest_client.rb +0 -58
  45. data/lib/abt/help.rb +0 -56
  46. data/lib/abt/providers/asana/clear.rb +0 -24
  47. data/lib/abt/providers/asana/clear_global.rb +0 -24
  48. data/lib/abt/providers/asana/current.rb +0 -69
  49. data/lib/abt/providers/asana/harvest_link_entry_data.rb +0 -48
  50. data/lib/abt/providers/asana/init.rb +0 -62
  51. data/lib/abt/providers/asana/move.rb +0 -54
  52. data/lib/abt/providers/asana/pick_task.rb +0 -46
  53. data/lib/abt/providers/asana/projects.rb +0 -30
  54. data/lib/abt/providers/asana/start.rb +0 -22
  55. data/lib/abt/providers/asana/tasks.rb +0 -35
  56. data/lib/abt/providers/harvest/clear.rb +0 -24
  57. data/lib/abt/providers/harvest/clear_global.rb +0 -24
  58. data/lib/abt/providers/harvest/current.rb +0 -79
  59. data/lib/abt/providers/harvest/init.rb +0 -61
  60. data/lib/abt/providers/harvest/pick_task.rb +0 -45
  61. data/lib/abt/providers/harvest/projects.rb +0 -29
  62. data/lib/abt/providers/harvest/start.rb +0 -58
  63. data/lib/abt/providers/harvest/stop.rb +0 -51
  64. data/lib/abt/providers/harvest/tasks.rb +0 -36
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Harvest
6
+ module Commands
7
+ class Projects < BaseCommand
8
+ def self.command
9
+ 'projects harvest'
10
+ end
11
+
12
+ def self.description
13
+ 'List all available projects - useful for piping into grep etc.'
14
+ end
15
+
16
+ def call
17
+ projects.map do |project|
18
+ print_project(project)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def projects
25
+ @projects ||= begin
26
+ cli.warn 'Fetching projects...'
27
+ project_assignments.map do |project_assignment|
28
+ project_assignment['project'].merge('client' => project_assignment['client'])
29
+ end
30
+ end
31
+ end
32
+
33
+ def project_assignments
34
+ @project_assignments ||= api.get_paged('users/me/project_assignments')
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Harvest
6
+ module Commands
7
+ class Share < BaseCommand
8
+ def self.command
9
+ 'share harvest[:<project-id>[/<task-id>]]'
10
+ end
11
+
12
+ def self.description
13
+ 'Print project/task config string'
14
+ end
15
+
16
+ def call
17
+ if project_id.nil?
18
+ cli.warn 'No project selected'
19
+ elsif task_id.nil?
20
+ cli.print_provider_command('harvest', project_id)
21
+ else
22
+ cli.print_provider_command('harvest', "#{project_id}/#{task_id}")
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Harvest
6
+ module Commands
7
+ class Start < BaseCommand
8
+ def self.command
9
+ 'start harvest[:<project-id>/<task-id>]'
10
+ end
11
+
12
+ def self.description
13
+ '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
14
+ end
15
+
16
+ def call
17
+ abort 'No current/provided task' if task_id.nil?
18
+
19
+ maybe_override_current_task
20
+
21
+ print_task(project, task)
22
+
23
+ cli.abort('No task selected') if task_id.nil?
24
+
25
+ create_time_entry
26
+
27
+ cli.warn 'Tracker successfully started'
28
+ rescue Abt::HttpError::HttpError => e
29
+ cli.warn e
30
+ cli.abort 'Unable to start tracker'
31
+ end
32
+
33
+ private
34
+
35
+ def maybe_override_current_task
36
+ return if arg_str.nil?
37
+ return if same_args_as_config?
38
+ return unless config.local_available?
39
+
40
+ should_override = cli.prompt_boolean 'Set selected task as current?'
41
+ Current.new(arg_str: arg_str, cli: cli).call if should_override
42
+ end
43
+
44
+ def create_time_entry
45
+ body = {
46
+ project_id: project_id,
47
+ task_id: task_id,
48
+ user_id: config.user_id,
49
+ spent_date: Date.today.iso8601
50
+ }
51
+
52
+ if external_link_data
53
+ body.merge! external_link_data
54
+ else
55
+ cli.warn 'No external link provided'
56
+ body[:notes] ||= cli.prompt('Fill in comment (optional)')
57
+ end
58
+
59
+ api.post('time_entries', Oj.dump(body, mode: :json))
60
+ end
61
+
62
+ def project
63
+ project_assignment['project']
64
+ end
65
+
66
+ def task
67
+ @task ||= project_assignment['task_assignments'].map { |ta| ta['task'] }.find do |task|
68
+ task['id'].to_s == task_id
69
+ end
70
+ end
71
+
72
+ def project_assignment
73
+ @project_assignment ||= begin
74
+ project_assignments.find { |pa| pa['project']['id'].to_s == project_id }
75
+ end
76
+ end
77
+
78
+ def project_assignments
79
+ @project_assignments ||= api.get_paged('users/me/project_assignments')
80
+ end
81
+
82
+ def external_link_data
83
+ @external_link_data ||= begin
84
+ arg_strs = cli.args.join(' ')
85
+ lines = `#{$PROGRAM_NAME} harvest-time-entry-data #{arg_strs}`.split("\n")
86
+
87
+ return if lines.empty?
88
+
89
+ # TODO: Make user choose which reference to use by printing the urls
90
+ if lines.length > 1
91
+ cli.abort('Multiple providers had harvest reference data, only one is supported at a time') # rubocop:disable Layout/LineLength
92
+ end
93
+
94
+ Oj.load(lines.first)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Harvest
6
+ module Commands
7
+ class Stop < BaseCommand
8
+ def self.command
9
+ 'stop harvest'
10
+ end
11
+
12
+ def self.description
13
+ 'Stop running harvest tracker'
14
+ end
15
+
16
+ def call
17
+ cli.abort 'No running time entry' if time_entry.nil?
18
+
19
+ stop_time_entry
20
+
21
+ cli.warn 'Harvest time entry stopped'
22
+ print_task(project, task)
23
+ rescue Abt::HttpError::HttpError => e
24
+ cli.warn e
25
+ cli.abort 'Unable to stop time entry'
26
+ end
27
+
28
+ private
29
+
30
+ def stop_time_entry
31
+ api.patch("time_entries/#{time_entry['id']}/stop")
32
+ end
33
+
34
+ def project
35
+ time_entry['project']
36
+ end
37
+
38
+ def task
39
+ time_entry['task']
40
+ end
41
+
42
+ def time_entry
43
+ @time_entry ||= begin
44
+ api.get_paged(
45
+ 'time_entries',
46
+ is_running: true,
47
+ user_id: config.user_id
48
+ ).first
49
+ rescue Abt::HttpError::HttpError => e # rubocop:disable Layout/RescueEnsureAlignment
50
+ cli.warn e
51
+ cli.abort 'Unable to fetch running time entry'
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Harvest
6
+ module Commands
7
+ class Tasks < BaseCommand
8
+ def self.command
9
+ 'tasks harvest'
10
+ end
11
+
12
+ def self.description
13
+ 'List available tasks on project - useful for piping into grep etc.'
14
+ end
15
+
16
+ def call
17
+ tasks.each do |task|
18
+ print_task(project, task)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def project
25
+ project_assignment['project']
26
+ end
27
+
28
+ def tasks
29
+ @tasks ||= project_assignment['task_assignments'].map { |ta| ta['task'] }
30
+ end
31
+
32
+ def project_assignment
33
+ @project_assignment ||= begin
34
+ project_assignments.find { |pa| pa['project']['id'].to_s == project_id }
35
+ end
36
+ end
37
+
38
+ def project_assignments
39
+ @project_assignments ||= api.get_paged('users/me/project_assignments')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Harvest
6
+ class Configuration
7
+ attr_accessor :cli
8
+
9
+ def initialize(cli:)
10
+ @cli = cli
11
+ @git = GitConfig.new(namespace: 'abt.harvest')
12
+ end
13
+
14
+ def local_available?
15
+ GitConfig.local_available?
16
+ end
17
+
18
+ def project_id
19
+ local_available? ? git['projectId'] : nil
20
+ end
21
+
22
+ def task_id
23
+ local_available? ? git['taskId'] : nil
24
+ end
25
+
26
+ def project_id=(value)
27
+ value = value.to_s unless value.nil?
28
+ return if project_id == value
29
+
30
+ clear_local
31
+ git['projectId'] = value
32
+ end
33
+
34
+ def task_id=(value)
35
+ value = value.to_s unless value.nil?
36
+ git['taskId'] = value
37
+ end
38
+
39
+ def clear_local
40
+ cli.abort 'No local configuration was found' unless local_available?
41
+
42
+ git['projectId'] = nil
43
+ git['taskId'] = nil
44
+ end
45
+
46
+ def clear_global
47
+ git.global['userId'] = nil
48
+ git.global['accountId'] = nil
49
+ git.global['accessToken'] = nil
50
+ end
51
+
52
+ def access_token
53
+ return git.global['accessToken'] unless git.global['accessToken'].nil?
54
+
55
+ git.global['accessToken'] = cli.prompt([
56
+ 'Please provide your personal access token for Harvest.',
57
+ 'If you don\'t have one, create one here: https://id.getharvest.com/developers',
58
+ '',
59
+ 'Enter access token'
60
+ ].join("\n"))
61
+ end
62
+
63
+ def account_id
64
+ return git.global['accountId'] unless git.global['accountId'].nil?
65
+
66
+ git.global['accountId'] = cli.prompt([
67
+ 'Please provide harvest account id.',
68
+ 'This information is shown next to your generated access token',
69
+ '',
70
+ 'Enter account id'
71
+ ].join("\n"))
72
+ end
73
+
74
+ def user_id
75
+ return git.global['userId'] unless git.global['userId'].nil?
76
+
77
+ git.global['userId'] = api.get('users/me')['id'].to_s
78
+ end
79
+
80
+ private
81
+
82
+ attr_reader :git
83
+
84
+ def api
85
+ @api ||=
86
+ Abt::Providers::Harvest::Api.new(access_token: access_token, account_id: account_id)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Abt
4
- VERSION = '0.0.2'
4
+ VERSION = '0.0.7'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: abt-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesper Sørensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-14 00:00:00.000000000 Z
11
+ date: 2021-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-inflector
@@ -75,39 +75,45 @@ extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
77
  - "./lib/abt.rb"
78
- - "./lib/abt/asana_client.rb"
79
78
  - "./lib/abt/cli.rb"
80
79
  - "./lib/abt/cli/dialogs.rb"
80
+ - "./lib/abt/cli/io.rb"
81
+ - "./lib/abt/docs.rb"
82
+ - "./lib/abt/docs/cli.rb"
83
+ - "./lib/abt/docs/markdown.rb"
81
84
  - "./lib/abt/git_config.rb"
82
- - "./lib/abt/harvest_client.rb"
83
- - "./lib/abt/help.rb"
84
- - "./lib/abt/help/cli.rb"
85
- - "./lib/abt/help/markdown.rb"
85
+ - "./lib/abt/helpers.rb"
86
86
  - "./lib/abt/http_error.rb"
87
87
  - "./lib/abt/providers.rb"
88
88
  - "./lib/abt/providers/asana.rb"
89
+ - "./lib/abt/providers/asana/api.rb"
89
90
  - "./lib/abt/providers/asana/base_command.rb"
90
- - "./lib/abt/providers/asana/clear.rb"
91
- - "./lib/abt/providers/asana/clear_global.rb"
92
- - "./lib/abt/providers/asana/current.rb"
93
- - "./lib/abt/providers/asana/harvest_link_entry_data.rb"
94
- - "./lib/abt/providers/asana/init.rb"
95
- - "./lib/abt/providers/asana/move.rb"
96
- - "./lib/abt/providers/asana/pick_task.rb"
97
- - "./lib/abt/providers/asana/projects.rb"
98
- - "./lib/abt/providers/asana/start.rb"
99
- - "./lib/abt/providers/asana/tasks.rb"
91
+ - "./lib/abt/providers/asana/commands/clear.rb"
92
+ - "./lib/abt/providers/asana/commands/clear_global.rb"
93
+ - "./lib/abt/providers/asana/commands/current.rb"
94
+ - "./lib/abt/providers/asana/commands/finalize.rb"
95
+ - "./lib/abt/providers/asana/commands/harvest_time_entry_data.rb"
96
+ - "./lib/abt/providers/asana/commands/init.rb"
97
+ - "./lib/abt/providers/asana/commands/pick.rb"
98
+ - "./lib/abt/providers/asana/commands/projects.rb"
99
+ - "./lib/abt/providers/asana/commands/share.rb"
100
+ - "./lib/abt/providers/asana/commands/start.rb"
101
+ - "./lib/abt/providers/asana/commands/tasks.rb"
102
+ - "./lib/abt/providers/asana/configuration.rb"
100
103
  - "./lib/abt/providers/harvest.rb"
104
+ - "./lib/abt/providers/harvest/api.rb"
101
105
  - "./lib/abt/providers/harvest/base_command.rb"
102
- - "./lib/abt/providers/harvest/clear.rb"
103
- - "./lib/abt/providers/harvest/clear_global.rb"
104
- - "./lib/abt/providers/harvest/current.rb"
105
- - "./lib/abt/providers/harvest/init.rb"
106
- - "./lib/abt/providers/harvest/pick_task.rb"
107
- - "./lib/abt/providers/harvest/projects.rb"
108
- - "./lib/abt/providers/harvest/start.rb"
109
- - "./lib/abt/providers/harvest/stop.rb"
110
- - "./lib/abt/providers/harvest/tasks.rb"
106
+ - "./lib/abt/providers/harvest/commands/clear.rb"
107
+ - "./lib/abt/providers/harvest/commands/clear_global.rb"
108
+ - "./lib/abt/providers/harvest/commands/current.rb"
109
+ - "./lib/abt/providers/harvest/commands/init.rb"
110
+ - "./lib/abt/providers/harvest/commands/pick.rb"
111
+ - "./lib/abt/providers/harvest/commands/projects.rb"
112
+ - "./lib/abt/providers/harvest/commands/share.rb"
113
+ - "./lib/abt/providers/harvest/commands/start.rb"
114
+ - "./lib/abt/providers/harvest/commands/stop.rb"
115
+ - "./lib/abt/providers/harvest/commands/tasks.rb"
116
+ - "./lib/abt/providers/harvest/configuration.rb"
111
117
  - "./lib/abt/version.rb"
112
118
  - bin/abt
113
119
  homepage: https://github.com/abtion/abt