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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/bin/abt +1 -1
  3. data/lib/abt.rb +6 -3
  4. data/lib/abt/cli.rb +91 -53
  5. data/lib/abt/cli/arguments_parser.rb +70 -0
  6. data/lib/abt/cli/base_command.rb +61 -0
  7. data/lib/abt/cli/{dialogs.rb → prompt.rb} +37 -18
  8. data/lib/abt/docs.rb +30 -24
  9. data/lib/abt/docs/cli.rb +42 -11
  10. data/lib/abt/docs/markdown.rb +38 -11
  11. data/lib/abt/git_config.rb +25 -14
  12. data/lib/abt/helpers.rb +1 -1
  13. data/lib/abt/providers/asana/base_command.rb +13 -13
  14. data/lib/abt/providers/asana/commands/add.rb +6 -6
  15. data/lib/abt/providers/asana/commands/branch_name.rb +44 -0
  16. data/lib/abt/providers/asana/commands/clear.rb +17 -6
  17. data/lib/abt/providers/asana/commands/current.rb +3 -3
  18. data/lib/abt/providers/asana/commands/finalize.rb +3 -3
  19. data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +3 -3
  20. data/lib/abt/providers/asana/commands/init.rb +5 -5
  21. data/lib/abt/providers/asana/commands/pick.rb +16 -8
  22. data/lib/abt/providers/asana/commands/projects.rb +3 -3
  23. data/lib/abt/providers/asana/commands/share.rb +5 -5
  24. data/lib/abt/providers/asana/commands/start.rb +14 -8
  25. data/lib/abt/providers/asana/commands/tasks.rb +3 -3
  26. data/lib/abt/providers/asana/configuration.rb +8 -16
  27. data/lib/abt/providers/devops/base_command.rb +14 -15
  28. data/lib/abt/providers/devops/commands/boards.rb +6 -4
  29. data/lib/abt/providers/devops/commands/branch_name.rb +45 -0
  30. data/lib/abt/providers/devops/commands/clear.rb +17 -6
  31. data/lib/abt/providers/devops/commands/current.rb +3 -3
  32. data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +3 -3
  33. data/lib/abt/providers/devops/commands/init.rb +5 -5
  34. data/lib/abt/providers/devops/commands/pick.rb +14 -7
  35. data/lib/abt/providers/devops/commands/share.rb +4 -4
  36. data/lib/abt/providers/devops/commands/work-items.rb +3 -3
  37. data/lib/abt/providers/devops/configuration.rb +7 -15
  38. data/lib/abt/providers/git.rb +19 -0
  39. data/lib/abt/providers/git/commands/branch.rb +74 -0
  40. data/lib/abt/providers/harvest/base_command.rb +13 -13
  41. data/lib/abt/providers/harvest/commands/clear.rb +17 -6
  42. data/lib/abt/providers/harvest/commands/current.rb +3 -3
  43. data/lib/abt/providers/harvest/commands/init.rb +5 -5
  44. data/lib/abt/providers/harvest/commands/pick.rb +15 -7
  45. data/lib/abt/providers/harvest/commands/projects.rb +3 -3
  46. data/lib/abt/providers/harvest/commands/share.rb +5 -5
  47. data/lib/abt/providers/harvest/commands/start.rb +6 -42
  48. data/lib/abt/providers/harvest/commands/stop.rb +3 -3
  49. data/lib/abt/providers/harvest/commands/tasks.rb +3 -3
  50. data/lib/abt/providers/harvest/commands/track.rb +49 -11
  51. data/lib/abt/providers/harvest/configuration.rb +7 -13
  52. data/lib/abt/version.rb +1 -1
  53. metadata +9 -7
  54. data/lib/abt/cli/io.rb +0 -23
  55. data/lib/abt/providers/asana/commands/clear_global.rb +0 -24
  56. data/lib/abt/providers/devops/commands/clear_global.rb +0 -24
  57. data/lib/abt/providers/harvest/commands/clear_global.rb +0 -24
@@ -5,17 +5,28 @@ module Abt
5
5
  module Harvest
6
6
  module Commands
7
7
  class Clear < BaseCommand
8
- def self.command
9
- 'clear harvest'
8
+ def self.usage
9
+ 'abt clear harvest'
10
10
  end
11
11
 
12
12
  def self.description
13
- 'Clear project/task for current git repository'
13
+ 'Clear harvest configuration'
14
14
  end
15
15
 
16
- def call
17
- cli.warn 'Clearing Harvest project configuration'
18
- config.clear_local
16
+ def self.flags
17
+ [
18
+ ['-g', '--global', 'Clear global instead of local harvest configuration (credentials etc.)'],
19
+ ['-a', '--all', 'Clear all harvest 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 Harvest
6
6
  module Commands
7
7
  class Current < BaseCommand
8
- def self.command
9
- 'current harvest[:<project-id>[/<task-id>]]'
8
+ def self.usage
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
- def call
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 Harvest
6
6
  module Commands
7
7
  class Init < BaseCommand
8
- def self.command
9
- 'init harvest'
8
+ def self.usage
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
- def call
16
+ def perform
17
17
  cli.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
@@ -31,14 +31,14 @@ module Abt
31
31
  cli.warn 'Select a project'
32
32
 
33
33
  loop do
34
- matches = matches_for_string cli.prompt('Enter search')
34
+ matches = matches_for_string cli.prompt.text('Enter search')
35
35
  if matches.empty?
36
36
  warn 'No matches'
37
37
  next
38
38
  end
39
39
 
40
40
  cli.warn 'Showing the 10 first matches' if matches.size > 10
41
- choice = cli.prompt_choice 'Select a project', matches[0...10], true
41
+ choice = cli.prompt.choice 'Select a project', matches[0...10], true
42
42
  break choice['project'] unless choice.nil?
43
43
  end
44
44
  end
@@ -5,25 +5,33 @@ module Abt
5
5
  module Harvest
6
6
  module Commands
7
7
  class Pick < BaseCommand
8
- def self.command
9
- 'pick harvest[:<project-id>]'
8
+ def self.usage
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
- def call
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
 
20
26
  cli.warn project['name']
21
- task = cli.prompt_choice 'Select a task', tasks
22
-
23
- config.project_id = project_id # We might have gotten the project ID as an argument
24
- config.task_id = task['id']
27
+ task = cli.prompt.choice 'Select a task', tasks
25
28
 
26
29
  print_task(project, task)
30
+
31
+ return if flags[:"dry-run"]
32
+
33
+ config.project_id = project_id # We might have gotten the project ID as a path
34
+ config.task_id = task['id']
27
35
  end
28
36
 
29
37
  private
@@ -5,15 +5,15 @@ module Abt
5
5
  module Harvest
6
6
  module Commands
7
7
  class Projects < BaseCommand
8
- def self.command
9
- 'projects harvest'
8
+ def self.usage
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
- def call
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 Harvest
6
6
  module Commands
7
7
  class Share < BaseCommand
8
- def self.command
9
- 'share harvest[:<project-id>[/<task-id>]]'
8
+ def self.usage
9
+ 'abt share harvest[:<project-id>[/<task-id>]]'
10
10
  end
11
11
 
12
12
  def self.description
13
13
  'Print project/task config string'
14
14
  end
15
15
 
16
- def call
16
+ def perform
17
17
  if project_id.nil?
18
18
  cli.warn 'No project selected'
19
19
  elsif task_id.nil?
20
- cli.print_provider_command('harvest', project_id)
20
+ cli.print_ari('harvest', project_id)
21
21
  else
22
- cli.print_provider_command('harvest', "#{project_id}/#{task_id}")
22
+ cli.print_ari('harvest', "#{project_id}/#{task_id}")
23
23
  end
24
24
  end
25
25
  end
@@ -1,54 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'track'
4
+
3
5
  module Abt
4
6
  module Providers
5
7
  module Harvest
6
8
  module Commands
7
- class Start < BaseCommand
8
- def self.command
9
- 'start harvest[:<project-id>/<task-id>]'
9
+ class Start < Track
10
+ def self.usage
11
+ 'abt start harvest[:<project-id>/<task-id>] [options]'
10
12
  end
11
13
 
12
14
  def self.description
13
- 'As track, but also lets the user override the current task and triggers `start` commands for other providers ' # rubocop:disable Layout/LineLength
14
- end
15
-
16
- def call
17
- track_output = call_track
18
- puts track_output
19
-
20
- use_arg_str(arg_str_from_track_output(track_output))
21
-
22
- maybe_override_current_task
23
- rescue Abt::HttpError::HttpError => e
24
- cli.warn e
25
- cli.abort 'Unable to start tracker'
26
- end
27
-
28
- private
29
-
30
- def arg_str_from_track_output(output)
31
- output = output.split(' # ').first
32
- output.split(':')[1]
33
- end
34
-
35
- def call_track
36
- input = StringIO.new(cli.args.join(' '))
37
- output = StringIO.new
38
- Abt::Cli.new(argv: ['track'], output: output, input: input).perform
39
-
40
- output.string.strip
41
- end
42
-
43
- def maybe_override_current_task
44
- return if arg_str.nil?
45
- return if same_args_as_config?
46
- return unless config.local_available?
47
- return unless cli.prompt_boolean 'Set selected task as current?'
48
-
49
- input = StringIO.new("harvest:#{project_id}/#{task_id}")
50
- output = StringIO.new
51
- Abt::Cli.new(argv: ['current'], output: output, input: input).perform
15
+ 'Alias for: `abt track harvest`. Meant to used in combination with other ARIs, e.g. `abt start harvest asana`'
52
16
  end
53
17
  end
54
18
  end
@@ -5,15 +5,15 @@ module Abt
5
5
  module Harvest
6
6
  module Commands
7
7
  class Stop < BaseCommand
8
- def self.command
9
- 'stop harvest'
8
+ def self.usage
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
- def call
16
+ def perform
17
17
  cli.abort 'No running time entry' if time_entry.nil?
18
18
 
19
19
  stop_time_entry
@@ -5,15 +5,15 @@ module Abt
5
5
  module Harvest
6
6
  module Commands
7
7
  class Tasks < BaseCommand
8
- def self.command
9
- 'tasks harvest'
8
+ def self.usage
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
- def call
16
+ def perform
17
17
  require_project!
18
18
 
19
19
  tasks.each do |task|
@@ -5,21 +5,30 @@ module Abt
5
5
  module Harvest
6
6
  module Commands
7
7
  class Track < BaseCommand
8
- def self.command
9
- 'track harvest[:<project-id>/<task-id>]'
8
+ def self.usage
9
+ 'abt track harvest[:<project-id>/<task-id>] [options]'
10
10
  end
11
11
 
12
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
13
+ 'Start tracker for current or specified task. Add a relevant ARI to link the time entry, e.g. `abt track harvest asana`'
14
14
  end
15
15
 
16
- def call
16
+ def self.flags
17
+ [
18
+ ['-s', '--set', 'Set specified task as current'],
19
+ ['-c', '--comment COMMENT', 'Override comment'],
20
+ ['-t', '--time HOURS', 'Set hours. Creates a stopped entry unless used with --running'],
21
+ ['-r', '--running', 'Used with --time, starts the created time entry']
22
+ ]
23
+ end
24
+
25
+ def perform
17
26
  require_task!
18
27
 
19
28
  print_task(created_time_entry['project'], created_time_entry['task'])
20
29
 
21
- cli.warn 'Tracker successfully started'
22
- rescue Abt::HttpError::HttpError => e
30
+ maybe_override_current_task
31
+ rescue Abt::HttpError::HttpError => _e
23
32
  cli.abort 'Invalid task'
24
33
  end
25
34
 
@@ -30,6 +39,19 @@ module Abt
30
39
  end
31
40
 
32
41
  def create_time_entry
42
+ body = time_entry_base_data
43
+ body.merge!(hours: flags[:time]) if flags.key? :time
44
+
45
+ result = api.post('time_entries', Oj.dump(body, mode: :json))
46
+
47
+ if flags.key?(:time) && flags[:running]
48
+ api.patch("time_entries/#{result['id']}/restart")
49
+ end
50
+
51
+ result
52
+ end
53
+
54
+ def time_entry_base_data
33
55
  body = {
34
56
  project_id: project_id,
35
57
  task_id: task_id,
@@ -38,18 +60,24 @@ module Abt
38
60
  }
39
61
 
40
62
  if external_link_data
63
+ cli.warn <<~TXT
64
+ Linking to:
65
+ #{external_link_data[:notes]}
66
+ #{external_link_data[:external_reference][:permalink]}
67
+ TXT
41
68
  body.merge! external_link_data
42
69
  else
43
70
  cli.warn 'No external link provided'
44
- body[:notes] ||= cli.prompt('Fill in comment (optional)')
45
71
  end
46
72
 
47
- api.post('time_entries', Oj.dump(body, mode: :json))
73
+ body[:notes] = flags[:comment] if flags.key?(:comment)
74
+ body[:notes] ||= cli.prompt.text('Fill in comment (optional)')
75
+ body
48
76
  end
49
77
 
50
78
  def external_link_data
51
79
  @external_link_data ||= begin
52
- input = StringIO.new(cli.args.join(' '))
80
+ input = StringIO.new(cli.aris.to_s)
53
81
  output = StringIO.new
54
82
  Abt::Cli.new(argv: ['harvest-time-entry-data'], output: output, input: input).perform
55
83
 
@@ -59,12 +87,22 @@ module Abt
59
87
 
60
88
  # TODO: Make user choose which reference to use by printing the urls
61
89
  if lines.length > 1
62
- cli.abort('Multiple providers had harvest reference data, only one is supported at a time') # rubocop:disable Layout/LineLength
90
+ cli.abort('Got reference data from multiple scheme providers, only one is supported at a time')
63
91
  end
64
92
 
65
- Oj.load(lines.first)
93
+ Oj.load(lines.first, symbol_keys: true)
66
94
  end
67
95
  end
96
+
97
+ def maybe_override_current_task
98
+ return unless flags[:set]
99
+ return if same_args_as_config?
100
+ return unless config.local_available?
101
+
102
+ input = StringIO.new("harvest:#{project_id}/#{task_id}")
103
+ output = StringIO.new
104
+ Abt::Cli.new(argv: ['current'], output: output, input: input).perform
105
+ end
68
106
  end
69
107
  end
70
108
  end
@@ -27,7 +27,7 @@ module Abt
27
27
  value = value.to_s unless value.nil?
28
28
  return if project_id == value
29
29
 
30
- clear_local
30
+ clear_local(verbose: false)
31
31
  git['projectId'] = value
32
32
  end
33
33
 
@@ -36,24 +36,18 @@ module Abt
36
36
  git['taskId'] = value
37
37
  end
38
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
39
+ def clear_local(verbose: true)
40
+ git.clear(output: verbose ? cli.err_output : nil)
44
41
  end
45
42
 
46
- def clear_global
47
- git.global.keys.each do |key|
48
- cli.puts 'Deleting configuration: ' + key
49
- git.global[key] = nil
50
- end
43
+ def clear_global(verbose: true)
44
+ git.global.clear(output: verbose ? cli.err_output : nil)
51
45
  end
52
46
 
53
47
  def access_token
54
48
  return git.global['accessToken'] unless git.global['accessToken'].nil?
55
49
 
56
- git.global['accessToken'] = cli.prompt([
50
+ git.global['accessToken'] = cli.prompt.text([
57
51
  'Please provide your personal access token for Harvest.',
58
52
  'If you don\'t have one, create one here: https://id.getharvest.com/developers',
59
53
  '',
@@ -64,7 +58,7 @@ module Abt
64
58
  def account_id
65
59
  return git.global['accountId'] unless git.global['accountId'].nil?
66
60
 
67
- git.global['accountId'] = cli.prompt([
61
+ git.global['accountId'] = cli.prompt.text([
68
62
  'Please provide harvest account id.',
69
63
  'This information is shown next to your generated access token',
70
64
  '',
data/lib/abt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Abt
4
- VERSION = '0.0.13'
4
+ VERSION = '0.0.18'
5
5
  end