abt-cli 0.0.15 → 0.0.20

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/bin/abt +1 -1
  3. data/lib/abt.rb +4 -3
  4. data/lib/abt/ari.rb +20 -0
  5. data/lib/abt/ari_list.rb +13 -0
  6. data/lib/abt/base_command.rb +63 -0
  7. data/lib/abt/cli.rb +68 -49
  8. data/lib/abt/cli/arguments_parser.rb +48 -0
  9. data/lib/abt/cli/prompt.rb +7 -6
  10. data/lib/abt/docs.rb +35 -28
  11. data/lib/abt/docs/cli.rb +42 -11
  12. data/lib/abt/docs/markdown.rb +38 -11
  13. data/lib/abt/git_config.rb +26 -31
  14. data/lib/abt/providers/asana/base_command.rb +17 -37
  15. data/lib/abt/providers/asana/commands/add.rb +12 -10
  16. data/lib/abt/providers/asana/commands/{branch-name.rb → branch_name.rb} +12 -7
  17. data/lib/abt/providers/asana/commands/clear.rb +19 -6
  18. data/lib/abt/providers/asana/commands/current.rb +22 -37
  19. data/lib/abt/providers/asana/commands/finalize.rb +8 -12
  20. data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +12 -7
  21. data/lib/abt/providers/asana/commands/init.rb +9 -9
  22. data/lib/abt/providers/asana/commands/pick.rb +28 -15
  23. data/lib/abt/providers/asana/commands/projects.rb +4 -4
  24. data/lib/abt/providers/asana/commands/share.rb +5 -9
  25. data/lib/abt/providers/asana/commands/start.rb +26 -18
  26. data/lib/abt/providers/asana/commands/tasks.rb +7 -6
  27. data/lib/abt/providers/asana/configuration.rb +23 -37
  28. data/lib/abt/providers/asana/path.rb +36 -0
  29. data/lib/abt/providers/devops/api.rb +12 -0
  30. data/lib/abt/providers/devops/base_command.rb +18 -44
  31. data/lib/abt/providers/devops/commands/boards.rb +7 -5
  32. data/lib/abt/providers/devops/commands/{branch-name.rb → branch_name.rb} +10 -6
  33. data/lib/abt/providers/devops/commands/clear.rb +19 -6
  34. data/lib/abt/providers/devops/commands/current.rb +17 -41
  35. data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +12 -4
  36. data/lib/abt/providers/devops/commands/init.rb +18 -18
  37. data/lib/abt/providers/devops/commands/pick.rb +16 -16
  38. data/lib/abt/providers/devops/commands/share.rb +6 -7
  39. data/lib/abt/providers/devops/commands/work-items.rb +4 -4
  40. data/lib/abt/providers/devops/configuration.rb +20 -57
  41. data/lib/abt/providers/devops/path.rb +50 -0
  42. data/lib/abt/providers/git/commands/branch.rb +28 -28
  43. data/lib/abt/providers/harvest/base_command.rb +18 -36
  44. data/lib/abt/providers/harvest/commands/clear.rb +19 -6
  45. data/lib/abt/providers/harvest/commands/current.rb +27 -34
  46. data/lib/abt/providers/harvest/commands/init.rb +8 -9
  47. data/lib/abt/providers/harvest/commands/pick.rb +15 -8
  48. data/lib/abt/providers/harvest/commands/projects.rb +4 -4
  49. data/lib/abt/providers/harvest/commands/share.rb +7 -11
  50. data/lib/abt/providers/harvest/commands/start.rb +6 -42
  51. data/lib/abt/providers/harvest/commands/stop.rb +10 -10
  52. data/lib/abt/providers/harvest/commands/tasks.rb +7 -4
  53. data/lib/abt/providers/harvest/commands/track.rb +66 -21
  54. data/lib/abt/providers/harvest/configuration.rb +23 -38
  55. data/lib/abt/providers/harvest/path.rb +36 -0
  56. data/lib/abt/version.rb +1 -1
  57. metadata +11 -7
  58. data/lib/abt/providers/asana/commands/clear_global.rb +0 -24
  59. data/lib/abt/providers/devops/commands/clear_global.rb +0 -24
  60. data/lib/abt/providers/harvest/commands/clear_global.rb +0 -24
@@ -3,40 +3,38 @@
3
3
  module Abt
4
4
  module Providers
5
5
  module Harvest
6
- class BaseCommand
7
- attr_reader :arg_str, :project_id, :task_id, :cli, :config
6
+ class BaseCommand < Abt::BaseCommand
7
+ extend Forwardable
8
8
 
9
- def initialize(arg_str:, cli:)
10
- @arg_str = arg_str
11
- @config = Configuration.new(cli: cli)
9
+ attr_reader :config, :path
12
10
 
13
- if arg_str.nil?
14
- use_current_args
15
- else
16
- use_arg_str(arg_str)
17
- end
18
- @cli = cli
11
+ def_delegators(:@path, :project_id, :task_id)
12
+
13
+ def initialize(ari:, cli:)
14
+ super
15
+
16
+ @config = Configuration.new(cli: cli)
17
+ @path = ari.path ? Path.new(ari.path) : config.path
19
18
  end
20
19
 
21
20
  private
22
21
 
23
22
  def require_project!
24
- cli.abort 'No current/specified project. Did you initialize Harvest?' if project_id.nil?
23
+ return if project_id
24
+
25
+ abort 'No current/specified project. Did you initialize Harvest?'
25
26
  end
26
27
 
27
28
  def require_task!
28
- if project_id.nil?
29
- cli.abort 'No current/specified project. Did you initialize Harvest and pick a task?'
29
+ unless project_id
30
+ abort 'No current/specified project. Did you initialize Harvest and pick a task?'
30
31
  end
31
- cli.abort 'No current/specified task. Did you pick a Harvest task?' if task_id.nil?
32
- end
33
32
 
34
- def same_args_as_config?
35
- project_id == config.project_id && task_id == config.task_id
33
+ abort 'No current/specified task. Did you pick a Harvest task?' if task_id.nil?
36
34
  end
37
35
 
38
36
  def print_project(project)
39
- cli.print_provider_command(
37
+ cli.print_ari(
40
38
  'harvest',
41
39
  project['id'],
42
40
  "#{project['client']['name']} > #{project['name']}"
@@ -44,29 +42,13 @@ module Abt
44
42
  end
45
43
 
46
44
  def print_task(project, task)
47
- cli.print_provider_command(
45
+ cli.print_ari(
48
46
  'harvest',
49
47
  "#{project['id']}/#{task['id']}",
50
48
  "#{project['name']} > #{task['name']}"
51
49
  )
52
50
  end
53
51
 
54
- def use_current_args
55
- @project_id = config.project_id
56
- @task_id = config.task_id
57
- end
58
-
59
- def use_arg_str(arg_str)
60
- args = arg_str.to_s.split('/')
61
- @project_id = args[0].to_s
62
- @project_id = nil if project_id.empty?
63
-
64
- return if project_id.nil?
65
-
66
- @task_id = args[1].to_s
67
- @task_id = nil if @task_id.empty?
68
- end
69
-
70
52
  def api
71
53
  @api ||= Abt::Providers::Harvest::Api.new(access_token: config.access_token,
72
54
  account_id: config.account_id)
@@ -5,17 +5,30 @@ 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]
30
+
31
+ warn 'Configuration cleared'
19
32
  end
20
33
  end
21
34
  end
@@ -5,66 +5,59 @@ 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
+ abort 'Must be run inside a git repository' unless config.local_available?
18
+
17
19
  require_project!
20
+ ensure_valid_configuration!
18
21
 
19
- if same_args_as_config? || !config.local_available?
20
- show_current_configuration
21
- else
22
- cli.warn 'Updating configuration'
23
- update_configuration
22
+ if path != config.path
23
+ config.path = path
24
+ warn 'Configuration updated'
24
25
  end
25
- end
26
-
27
- private
28
26
 
29
- def show_current_configuration
30
- if task_id.nil?
31
- print_project(project)
32
- else
33
- print_task(project, task)
34
- end
27
+ print_configuration
35
28
  end
36
29
 
37
- def update_configuration
38
- ensure_project_is_valid!
39
- config.project_id = project_id
30
+ private
40
31
 
32
+ def print_configuration
41
33
  if task_id.nil?
42
34
  print_project(project)
43
- config.task_id = nil
44
35
  else
45
- ensure_task_is_valid!
46
- config.task_id = task_id
47
-
48
36
  print_task(project, task)
49
37
  end
50
38
  end
51
39
 
52
- def ensure_project_is_valid!
53
- cli.abort "Invalid project: #{project_id}" if project.nil?
54
- end
55
-
56
- def ensure_task_is_valid!
57
- cli.abort "Invalid task: #{task_id}" if task.nil?
40
+ def ensure_valid_configuration!
41
+ abort "Invalid project: #{project_id}" if project.nil?
42
+ abort "Invalid task: #{task_id}" if task_id && task.nil?
58
43
  end
59
44
 
60
45
  def project
61
- @project ||= project_assignment['project'].merge('client' => project_assignment['client'])
46
+ return @project if instance_variable_defined? :@project
47
+
48
+ @project = if project_assignment
49
+ project_assignment['project'].merge('client' => project_assignment['client'])
50
+ end
62
51
  end
63
52
 
64
53
  def task
65
- @task ||= project_assignment['task_assignments'].map { |ta| ta['task'] }.find do |task|
66
- task['id'].to_s == task_id
67
- end
54
+ return @task if instance_variable_defined? :@task
55
+
56
+ @task = if project_assignment
57
+ project_assignment['task_assignments'].map { |ta| ta['task'] }.find do |task|
58
+ task['id'].to_s == task_id
59
+ end
60
+ end
68
61
  end
69
62
 
70
63
  def project_assignment
@@ -5,22 +5,21 @@ 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
17
- cli.abort 'Must be run inside a git repository' unless config.local_available?
16
+ def perform
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
20
  project = find_search_result
21
21
 
22
- config.project_id = project['id']
23
- config.task_id = nil
22
+ config.path = Path.from_ids(project['id'])
24
23
 
25
24
  print_project(project)
26
25
  end
@@ -28,7 +27,7 @@ module Abt
28
27
  private
29
28
 
30
29
  def find_search_result
31
- cli.warn 'Select a project'
30
+ warn 'Select a project'
32
31
 
33
32
  loop do
34
33
  matches = matches_for_string cli.prompt.text('Enter search')
@@ -37,7 +36,7 @@ module Abt
37
36
  next
38
37
  end
39
38
 
40
- cli.warn 'Showing the 10 first matches' if matches.size > 10
39
+ warn 'Showing the 10 first matches' if matches.size > 10
41
40
  choice = cli.prompt.choice 'Select a project', matches[0...10], true
42
41
  break choice['project'] unless choice.nil?
43
42
  end
@@ -66,7 +65,7 @@ module Abt
66
65
 
67
66
  def projects
68
67
  @projects ||= begin
69
- cli.warn 'Fetching projects...'
68
+ warn 'Fetching projects...'
70
69
  project_assignments.map do |project_assignment|
71
70
  project_assignment['project'].merge('client' => project_assignment['client'])
72
71
  end
@@ -5,25 +5,32 @@ 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
17
- cli.abort 'Must be run inside a git repository' unless config.local_available?
16
+ def self.flags
17
+ [
18
+ ['-d', '--dry-run', 'Keep existing configuration']
19
+ ]
20
+ end
21
+
22
+ def perform
23
+ abort 'Must be run inside a git repository' unless config.local_available?
18
24
  require_project!
19
25
 
20
- cli.warn project['name']
26
+ warn project['name']
21
27
  task = cli.prompt.choice 'Select a task', tasks
22
28
 
23
- config.project_id = project_id # We might have gotten the project ID as an argument
24
- config.task_id = task['id']
25
-
26
29
  print_task(project, task)
30
+
31
+ return if flags[:"dry-run"]
32
+
33
+ config.path = Path.from_ids(project_id, task['id'])
27
34
  end
28
35
 
29
36
  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
@@ -23,7 +23,7 @@ module Abt
23
23
 
24
24
  def projects
25
25
  @projects ||= begin
26
- cli.warn 'Fetching projects...'
26
+ warn 'Fetching projects...'
27
27
  project_assignments.map do |project_assignment|
28
28
  project_assignment['project'].merge('client' => project_assignment['client'])
29
29
  end
@@ -5,22 +5,18 @@ 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
- 'Print project/task config string'
13
+ 'Print project/task ARI'
14
14
  end
15
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
16
+ def perform
17
+ require_project!
18
+
19
+ cli.print_ari('harvest', path)
24
20
  end
25
21
  end
26
22
  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,30 +5,30 @@ 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
17
- cli.abort 'No running time entry' if time_entry.nil?
16
+ def perform
17
+ abort 'No running time entry' if time_entry.nil?
18
18
 
19
19
  stop_time_entry
20
20
 
21
- cli.warn 'Harvest time entry stopped'
21
+ warn 'Harvest time entry stopped'
22
22
  print_task(project, task)
23
- rescue Abt::HttpError::HttpError => e
24
- cli.warn e
25
- cli.abort 'Unable to stop time entry'
26
23
  end
27
24
 
28
25
  private
29
26
 
30
27
  def stop_time_entry
31
28
  api.patch("time_entries/#{time_entry['id']}/stop")
29
+ rescue Abt::HttpError::HttpError => e
30
+ warn e
31
+ abort 'Unable to stop time entry'
32
32
  end
33
33
 
34
34
  def project
@@ -47,8 +47,8 @@ module Abt
47
47
  user_id: config.user_id
48
48
  ).first
49
49
  rescue Abt::HttpError::HttpError => e # rubocop:disable Layout/RescueEnsureAlignment
50
- cli.warn e
51
- cli.abort 'Unable to fetch running time entry'
50
+ warn e
51
+ abort 'Unable to fetch running time entry'
52
52
  end
53
53
  end
54
54
  end