abt-cli 0.0.15 → 0.0.16

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/bin/abt +1 -1
  3. data/lib/abt.rb +4 -3
  4. data/lib/abt/cli.rb +70 -48
  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/prompt.rb +2 -2
  8. data/lib/abt/docs.rb +24 -18
  9. data/lib/abt/docs/cli.rb +42 -11
  10. data/lib/abt/docs/markdown.rb +36 -10
  11. data/lib/abt/git_config.rb +11 -0
  12. data/lib/abt/providers/asana/base_command.rb +13 -13
  13. data/lib/abt/providers/asana/commands/add.rb +3 -3
  14. data/lib/abt/providers/asana/commands/{branch-name.rb → branch_name.rb} +3 -3
  15. data/lib/abt/providers/asana/commands/clear.rb +17 -6
  16. data/lib/abt/providers/asana/commands/current.rb +3 -3
  17. data/lib/abt/providers/asana/commands/finalize.rb +3 -3
  18. data/lib/abt/providers/asana/commands/harvest_time_entry_data.rb +3 -3
  19. data/lib/abt/providers/asana/commands/init.rb +3 -3
  20. data/lib/abt/providers/asana/commands/pick.rb +13 -5
  21. data/lib/abt/providers/asana/commands/projects.rb +3 -3
  22. data/lib/abt/providers/asana/commands/share.rb +5 -5
  23. data/lib/abt/providers/asana/commands/start.rb +13 -7
  24. data/lib/abt/providers/asana/commands/tasks.rb +3 -3
  25. data/lib/abt/providers/asana/configuration.rb +5 -13
  26. data/lib/abt/providers/devops/base_command.rb +14 -15
  27. data/lib/abt/providers/devops/commands/boards.rb +6 -4
  28. data/lib/abt/providers/devops/commands/{branch-name.rb → branch_name.rb} +3 -3
  29. data/lib/abt/providers/devops/commands/clear.rb +17 -6
  30. data/lib/abt/providers/devops/commands/current.rb +3 -3
  31. data/lib/abt/providers/devops/commands/harvest_time_entry_data.rb +3 -3
  32. data/lib/abt/providers/devops/commands/init.rb +3 -3
  33. data/lib/abt/providers/devops/commands/pick.rb +12 -5
  34. data/lib/abt/providers/devops/commands/share.rb +4 -4
  35. data/lib/abt/providers/devops/commands/work-items.rb +3 -3
  36. data/lib/abt/providers/devops/configuration.rb +5 -13
  37. data/lib/abt/providers/git/commands/branch.rb +15 -21
  38. data/lib/abt/providers/harvest/base_command.rb +13 -13
  39. data/lib/abt/providers/harvest/commands/clear.rb +17 -6
  40. data/lib/abt/providers/harvest/commands/current.rb +3 -3
  41. data/lib/abt/providers/harvest/commands/init.rb +3 -3
  42. data/lib/abt/providers/harvest/commands/pick.rb +13 -5
  43. data/lib/abt/providers/harvest/commands/projects.rb +3 -3
  44. data/lib/abt/providers/harvest/commands/share.rb +5 -5
  45. data/lib/abt/providers/harvest/commands/start.rb +6 -42
  46. data/lib/abt/providers/harvest/commands/stop.rb +3 -3
  47. data/lib/abt/providers/harvest/commands/tasks.rb +3 -3
  48. data/lib/abt/providers/harvest/commands/track.rb +49 -11
  49. data/lib/abt/providers/harvest/configuration.rb +5 -11
  50. data/lib/abt/version.rb +1 -1
  51. metadata +6 -7
  52. data/lib/abt/providers/asana/commands/clear_global.rb +0 -24
  53. data/lib/abt/providers/devops/commands/clear_global.rb +0 -24
  54. data/lib/abt/providers/harvest/commands/clear_global.rb +0 -24
@@ -5,21 +5,21 @@ module Abt
5
5
  module Asana
6
6
  module Commands
7
7
  class Share < BaseCommand
8
- def self.command
9
- 'share asana[:<project-gid>[/<task-gid>]]'
8
+ def self.usage
9
+ 'abt share asana[:<project-gid>[/<task-gid>]]'
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
  require_project!
18
18
 
19
19
  if task_gid.nil?
20
- cli.print_provider_command('asana', project_gid)
20
+ cli.print_scheme_argument('asana', project_gid)
21
21
  else
22
- cli.print_provider_command('asana', "#{project_gid}/#{task_gid}")
22
+ cli.print_scheme_argument('asana', "#{project_gid}/#{task_gid}")
23
23
  end
24
24
  end
25
25
  end
@@ -5,15 +5,21 @@ module Abt
5
5
  module Asana
6
6
  module Commands
7
7
  class Start < BaseCommand
8
- def self.command
9
- 'start asana[:<project-gid>/<task-gid>]'
8
+ def self.usage
9
+ 'abt start asana[:<project-gid>/<task-gid>]'
10
10
  end
11
11
 
12
12
  def self.description
13
- 'Set current task and move it to a section (column) of your choice'
13
+ 'Move current or specified task to WIP section (column) and assign it to you'
14
14
  end
15
15
 
16
- def call
16
+ def self.flags
17
+ [
18
+ ['-s', '--set', 'Set specified task as current']
19
+ ]
20
+ end
21
+
22
+ def perform
17
23
  require_task!
18
24
 
19
25
  maybe_override_current_task
@@ -25,12 +31,12 @@ module Abt
25
31
  private
26
32
 
27
33
  def maybe_override_current_task
28
- return if arg_str.nil?
34
+ return unless flags[:set]
35
+ return if path.nil?
29
36
  return if same_args_as_config?
30
37
  return unless config.local_available?
31
38
 
32
- should_override = cli.prompt.boolean 'Set selected task as current?'
33
- Current.new(arg_str: arg_str, cli: cli).call if should_override
39
+ Current.new(path: path, cli: cli).call
34
40
  end
35
41
 
36
42
  def update_assignee_if_needed
@@ -5,15 +5,15 @@ module Abt
5
5
  module Asana
6
6
  module Commands
7
7
  class Tasks < BaseCommand
8
- def self.command
9
- 'tasks asana'
8
+ def self.usage
9
+ 'abt tasks asana'
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|
@@ -49,7 +49,7 @@ module Abt
49
49
  def project_gid=(value)
50
50
  return if project_gid == value
51
51
 
52
- clear_local
52
+ clear_local(verbose: false)
53
53
  git['projectGid'] = value unless value.nil?
54
54
  end
55
55
 
@@ -57,20 +57,12 @@ module Abt
57
57
  git['taskGid'] = value
58
58
  end
59
59
 
60
- def clear_local
61
- cli.abort 'No local configuration was found' unless local_available?
62
-
63
- git['projectGid'] = nil
64
- git['taskGid'] = nil
65
- git['wipSectionGid'] = nil
66
- git['finalizedSectionGid'] = nil
60
+ def clear_local(verbose: true)
61
+ git.clear(output: verbose ? cli.err_output : nil)
67
62
  end
68
63
 
69
- def clear_global
70
- git.global.keys.each do |key|
71
- cli.puts 'Deleting configuration: ' + key
72
- git.global[key] = nil
73
- end
64
+ def clear_global(verbose: true)
65
+ git.global.clear(output: verbose ? cli.err_output : nil)
74
66
  end
75
67
 
76
68
  def access_token
@@ -3,19 +3,18 @@
3
3
  module Abt
4
4
  module Providers
5
5
  module Devops
6
- class BaseCommand
7
- attr_reader :arg_str, :organization_name, :project_name, :board_id, :work_item_id, :cli, :config
6
+ class BaseCommand < Abt::Cli::BaseCommand
7
+ attr_reader :organization_name, :project_name, :board_id, :work_item_id, :config
8
8
 
9
- def initialize(arg_str:, cli:)
10
- @arg_str = arg_str
9
+ def initialize(path:, cli:, **)
10
+ super
11
11
 
12
12
  @config = Configuration.new(cli: cli)
13
- @cli = cli
14
13
 
15
- if arg_str.nil?
16
- use_current_args
14
+ if path.nil?
15
+ use_current_path
17
16
  else
18
- use_arg_str(arg_str)
17
+ use_path(path)
19
18
  end
20
19
  end
21
20
 
@@ -55,28 +54,28 @@ module Abt
55
54
  end
56
55
 
57
56
  def print_board(organization_name, project_name, board)
58
- arg_str = "#{organization_name}/#{project_name}/#{board['id']}"
57
+ path = "#{organization_name}/#{project_name}/#{board['id']}"
59
58
 
60
- cli.print_provider_command('devops', arg_str, board['name'])
59
+ cli.print_scheme_argument('devops', path, board['name'])
61
60
  # cli.warn board['url'] if board.key?('url') && cli.output.isatty # TODO: Web URL
62
61
  end
63
62
 
64
63
  def print_work_item(organization, project, board, work_item)
65
- arg_str = "#{organization}/#{project}/#{board['id']}/#{work_item['id']}"
64
+ path = "#{organization}/#{project}/#{board['id']}/#{work_item['id']}"
66
65
 
67
- cli.print_provider_command('devops', arg_str, work_item['name'])
66
+ cli.print_scheme_argument('devops', path, work_item['name'])
68
67
  cli.warn work_item['url'] if work_item.key?('url') && cli.output.isatty
69
68
  end
70
69
 
71
- def use_current_args
70
+ def use_current_path
72
71
  @organization_name = config.organization_name
73
72
  @project_name = config.project_name
74
73
  @board_id = config.board_id
75
74
  @work_item_id = config.work_item_id
76
75
  end
77
76
 
78
- def use_arg_str(arg_str)
79
- args = arg_str.to_s.split('/')
77
+ def use_path(path)
78
+ args = path.to_s.split('/')
80
79
 
81
80
  if args.length < 3
82
81
  cli.abort 'Argument format is <organization>/<project>/<board-id>[/<work-item-id>]'
@@ -5,16 +5,18 @@ module Abt
5
5
  module Devops
6
6
  module Commands
7
7
  class Boards < BaseCommand
8
- def self.command
9
- 'boards devops'
8
+ def self.usage
9
+ 'abt boards devops'
10
10
  end
11
11
 
12
12
  def self.description
13
13
  'List all boards - useful for piping into grep etc'
14
14
  end
15
15
 
16
- def call
17
- cli.abort 'No organization selected. Did you initialize DevOps?' if organization_name.nil?
16
+ def perform
17
+ if organization_name.nil?
18
+ cli.abort 'No organization selected. Did you initialize DevOps?'
19
+ end
18
20
  cli.abort 'No project selected. Did you initialize DevOps?' if project_name.nil?
19
21
 
20
22
  boards.map do |board|
@@ -5,15 +5,15 @@ module Abt
5
5
  module Devops
6
6
  module Commands
7
7
  class BranchName < BaseCommand
8
- def self.command
9
- 'branch-name devops[:<organization-name>/<project-name>/<board-id>/<work-item-id>]'
8
+ def self.usage
9
+ 'abt branch-name devops[:<organization-name>/<project-name>/<board-id>/<work-item-id>]'
10
10
  end
11
11
 
12
12
  def self.description
13
13
  'Suggest a git branch name for the current/specified work-item.'
14
14
  end
15
15
 
16
- def call
16
+ def perform
17
17
  require_work_item!
18
18
 
19
19
  cli.puts name
@@ -5,17 +5,28 @@ module Abt
5
5
  module Devops
6
6
  module Commands
7
7
  class Clear < BaseCommand
8
- def self.command
9
- 'clear devops'
8
+ def self.usage
9
+ 'abt clear devops'
10
10
  end
11
11
 
12
12
  def self.description
13
- 'Clear DevOps config for current git repository'
13
+ 'Clear DevOps configuration'
14
14
  end
15
15
 
16
- def call
17
- cli.warn 'Clearing configuration'
18
- config.clear_local
16
+ def self.flags
17
+ [
18
+ ['-g', '--global', 'Clear global instead of local DevOp configuration (credentials etc.)'],
19
+ ['-a', '--all', 'Clear all DevOp 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 Devops
6
6
  module Commands
7
7
  class Current < BaseCommand
8
- def self.command
9
- 'current devops[:<organization-name>/<project-name>/<board-id>[/<work-item-id>]]'
8
+ def self.usage
9
+ 'abt current devops[:<organization-name>/<project-name>/<board-id>[/<work-item-id>]]'
10
10
  end
11
11
 
12
12
  def self.description
13
13
  'Get or set DevOps configuration for current git repository'
14
14
  end
15
15
 
16
- def call
16
+ def perform
17
17
  require_board!
18
18
 
19
19
  if same_args_as_config? || !config.local_available?
@@ -5,15 +5,15 @@ module Abt
5
5
  module Devops
6
6
  module Commands
7
7
  class HarvestTimeEntryData < BaseCommand
8
- def self.command
9
- 'harvest-time-entry-data devops[:<organization-name>/<project-name>/<board-id>/<work-item-id>]'
8
+ def self.usage
9
+ 'abt harvest-time-entry-data devops[:<organization-name>/<project-name>/<board-id>/<work-item-id>]'
10
10
  end
11
11
 
12
12
  def self.description
13
13
  'Print Harvest time entry data for DevOps work item as json. Used by harvest start script.'
14
14
  end
15
15
 
16
- def call
16
+ def perform
17
17
  require_work_item!
18
18
 
19
19
  body = {
@@ -8,15 +8,15 @@ module Abt
8
8
  AZURE_DEV_URL_REGEX = %r{^https://dev\.azure\.com/(?<organization>[^/]+)/(?<project>[^/]+)}.freeze
9
9
  VS_URL_REGEX = %r{^https://(?<organization>[^.]+)\.visualstudio\.com/(?<project>[^/]+)}.freeze
10
10
 
11
- def self.command
12
- 'init devops'
11
+ def self.usage
12
+ 'abt init devops'
13
13
  end
14
14
 
15
15
  def self.description
16
16
  'Pick DevOps board for current git repository'
17
17
  end
18
18
 
19
- def call
19
+ def perform
20
20
  cli.abort 'Must be run inside a git repository' unless config.local_available?
21
21
 
22
22
  @organization_name = config.organization_name = organization_name_from_url
@@ -5,25 +5,32 @@ module Abt
5
5
  module Devops
6
6
  module Commands
7
7
  class Pick < BaseCommand
8
- def self.command
9
- 'pick devops[:<organization-name>/<project-name>/<board-id>]'
8
+ def self.usage
9
+ 'abt pick devops[:<organization-name>/<project-name>/<board-id>]'
10
10
  end
11
11
 
12
12
  def self.description
13
13
  'Pick work item 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_board!
19
25
 
20
26
  cli.warn "#{project_name} - #{board['name']}"
21
27
 
22
28
  work_item = select_work_item
29
+ print_work_item(organization_name, project_name, board, work_item)
23
30
 
24
- update_config!(work_item)
31
+ return if flags[:"dry-run"]
25
32
 
26
- print_work_item(organization_name, project_name, board, work_item)
33
+ update_config!(work_item)
27
34
  end
28
35
 
29
36
  private
@@ -5,19 +5,19 @@ module Abt
5
5
  module Devops
6
6
  module Commands
7
7
  class Share < BaseCommand
8
- def self.command
9
- 'share devops[:<organization-name>/<project-name>/<board-id>[/<work-item-id>]]'
8
+ def self.usage
9
+ 'abt share devops[:<organization-name>/<project-name>/<board-id>[/<work-item-id>]]'
10
10
  end
11
11
 
12
12
  def self.description
13
13
  'Print DevOps config string'
14
14
  end
15
15
 
16
- def call
16
+ def perform
17
17
  require_work_item!
18
18
 
19
19
  args = [organization_name, project_name, board_id, work_item_id].compact
20
- cli.print_provider_command('devops', args.join('/'))
20
+ cli.print_scheme_argument('devops', args.join('/'))
21
21
  end
22
22
  end
23
23
  end
@@ -5,15 +5,15 @@ module Abt
5
5
  module Devops
6
6
  module Commands
7
7
  class WorkItems < BaseCommand
8
- def self.command
9
- 'work-items devops'
8
+ def self.usage
9
+ 'abt work-items devops'
10
10
  end
11
11
 
12
12
  def self.description
13
13
  'List all work items on board - useful for piping into grep etc.'
14
14
  end
15
15
 
16
- def call
16
+ def perform
17
17
  require_board!
18
18
 
19
19
  work_items.each do |work_item|
@@ -34,7 +34,7 @@ module Abt
34
34
  def organization_name=(value)
35
35
  return if organization_name == value
36
36
 
37
- clear_local
37
+ clear_local(verbose: false)
38
38
  git['organizationName'] = value unless value.nil?
39
39
  end
40
40
 
@@ -57,20 +57,12 @@ module Abt
57
57
  git['workItemId'] = value
58
58
  end
59
59
 
60
- def clear_local
61
- cli.abort 'No local configuration was found' unless local_available?
62
-
63
- git['organizationName'] = nil
64
- git['projectName'] = nil
65
- git['boardId'] = nil
66
- git['workItemId'] = nil
60
+ def clear_local(verbose: true)
61
+ git.clear(output: verbose ? cli.err_output : nil)
67
62
  end
68
63
 
69
- def clear_global
70
- git.global.keys.each do |key|
71
- cli.puts 'Deleting configuration: ' + key
72
- git.global[key] = nil
73
- end
64
+ def clear_global(verbose: true)
65
+ git.global.clear(output: verbose ? cli.err_output : nil)
74
66
  end
75
67
 
76
68
  def username_for_organization(organization_name)
@@ -4,22 +4,16 @@ module Abt
4
4
  module Providers
5
5
  module Git
6
6
  module Commands
7
- class Branch
8
- attr_reader :cli
9
-
10
- def self.command
11
- 'branch git <provider>'
7
+ class Branch < Abt::Cli::BaseCommand
8
+ def self.usage
9
+ 'abt branch git <scheme>[:<path>]'
12
10
  end
13
11
 
14
12
  def self.description
15
- 'Switch branch. Uses a compatible provider to generate the branch-name: E.g. `abt branch git asana`'
16
- end
17
-
18
- def initialize(cli:, **)
19
- @cli = cli
13
+ 'Switch branch. Uses a compatible scheme to generate the branch-name: E.g. `abt branch git asana`'
20
14
  end
21
15
 
22
- def call
16
+ def perform
23
17
  create_and_switch unless switch
24
18
  cli.warn "Switched to #{branch_name}"
25
19
  end
@@ -45,29 +39,29 @@ module Abt
45
39
 
46
40
  def branch_name # rubocop:disable Metrics/MethodLength
47
41
  @branch_name ||= begin
48
- if branch_names_from_providers.empty?
42
+ if branch_names_from_scheme_arguments.empty?
49
43
  cli.abort [
50
- 'None of the specified providers responded to `branch-name`.',
51
- 'Did you add compatible provider? e.g.:',
44
+ 'None of the specified scheme arguments responded to `branch-name`.',
45
+ 'Did you add compatible scheme? e.g.:',
52
46
  ' abt branch git asana',
53
47
  ' abt branch git devops'
54
48
  ].join("\n")
55
49
  end
56
50
 
57
- if branch_names_from_providers.length > 1
51
+ if branch_names_from_scheme_arguments.length > 1
58
52
  cli.abort [
59
- 'Got branch names from multiple providers, only one is supported',
60
- 'Branch names where:',
61
- *branch_names_from_providers.map { |name| " #{name}" }
53
+ 'Got branch names from multiple scheme arguments, only one is supported',
54
+ 'Branch names were:',
55
+ *branch_names_from_scheme_arguments.map { |name| " #{name}" }
62
56
  ].join("\n")
63
57
  end
64
58
 
65
- branch_names_from_providers.first
59
+ branch_names_from_scheme_arguments.first
66
60
  end
67
61
  end
68
62
 
69
- def branch_names_from_providers
70
- input = StringIO.new(cli.args.join(' '))
63
+ def branch_names_from_scheme_arguments
64
+ input = StringIO.new(cli.scheme_arguments.to_s)
71
65
  output = StringIO.new
72
66
  Abt::Cli.new(argv: ['branch-name'], output: output, input: input).perform
73
67