abt-cli 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0cc34f7579a887a49ae83db56c8b3808a0e00b09c55631f9b4224228477a0762
4
- data.tar.gz: 9c26a06c3af53ebe55ca5e53f93b5d6d73854962daebef31d131000657be1c63
3
+ metadata.gz: 4f1631b9069ca5094ba301eb3ccc5cf42da8e48a85b2678e8499cea1e9e4551c
4
+ data.tar.gz: cd9dc57e8a6276de5a2bca61e59fb537bc8887901615d7ec86f2c4a59145f76c
5
5
  SHA512:
6
- metadata.gz: 4fe10297a130b747d93dc1398bdf404996d5c07987680deac59a5365d6893ab3d0466ebd764ef087f5eb2409b99a7733dc55a869432d81286f3460ec510d247d
7
- data.tar.gz: 3684a1d3113f9df06637a6c7294f334b48e2c8cd5e54d4334c1ec1884571519f6e5aedeec327d8292f5364d1251453d6a7a8131074f91b2f94935b7a3586ddb9
6
+ metadata.gz: bdca57213f85db7a3604ac1a5ed50a16a2918fded5b3b3e090e52aeb184414345d7609f08ef5145f205cf3fb9f1576f9e0aaa6b25a2e41684cfd506bed19e851
7
+ data.tar.gz: d7eb95a22516aa0f894262e0a1b52ee659736b88775936040a87db03260711e12dbc6764674799b5d2f8bdb86cb14495f01440a0703d300759c3482db17a810a
@@ -24,18 +24,18 @@ module Abt
24
24
  end
25
25
  end
26
26
 
27
- def prompt_choice(text, options, allow_back_option = false)
27
+ def prompt_choice(text, options, nil_option = false)
28
28
  warn "#{text}:"
29
29
 
30
30
  if options.length.zero?
31
- abort 'No available options' unless allow_back_option
31
+ abort 'No available options' unless nil_option
32
32
 
33
33
  warn 'No available options'
34
34
  return nil
35
35
  end
36
36
 
37
37
  print_options(options)
38
- select_options(options, allow_back_option)
38
+ select_options(options, nil_option)
39
39
  end
40
40
 
41
41
  private
@@ -46,11 +46,11 @@ module Abt
46
46
  end
47
47
  end
48
48
 
49
- def select_options(options, allow_back_option)
49
+ def select_options(options, nil_option)
50
50
  loop do
51
- number = read_option_number(options.length, allow_back_option)
51
+ number = read_option_number(options.length, nil_option)
52
52
  if number.nil?
53
- return nil if allow_back_option
53
+ return nil if nil_option
54
54
 
55
55
  next
56
56
  end
@@ -62,12 +62,12 @@ module Abt
62
62
  end
63
63
  end
64
64
 
65
- def read_option_number(options_length, allow_back_option)
66
- err_output.print "(1-#{options_length}#{allow_back_option ? ', q: back' : ''}): "
65
+ def read_option_number(options_length, nil_option)
66
+ err_output.print "(1-#{options_length}#{nil_option_string(nil_option)}): "
67
67
 
68
68
  input = read_user_input
69
69
 
70
- return nil if allow_back_option && input == 'q'
70
+ return nil if nil_option && input == nil_option_character(nil_option)
71
71
 
72
72
  option_number = input.to_i
73
73
  if option_number <= 0 || option_number > options_length
@@ -78,6 +78,25 @@ module Abt
78
78
  option_number
79
79
  end
80
80
 
81
+ def nil_option_string(nil_option)
82
+ return '' unless nil_option
83
+
84
+ ", #{nil_option_character(nil_option)}: #{nil_option_description(nil_option)}"
85
+ end
86
+
87
+ def nil_option_character(nil_option)
88
+ return 'q' if nil_option == true
89
+
90
+ nil_option[0]
91
+ end
92
+
93
+ def nil_option_description(nil_option)
94
+ return 'back' if nil_option == true
95
+ return nil_option if nil_option.is_a?(String)
96
+
97
+ nil_option[1]
98
+ end
99
+
81
100
  def read_user_input
82
101
  open('/dev/tty', &:gets).strip
83
102
  end
@@ -20,6 +20,17 @@ module Abt
20
20
 
21
21
  private
22
22
 
23
+ def require_project!
24
+ cli.abort 'No current/specified project. Did you initialize Asana?' if project_gid.nil?
25
+ end
26
+
27
+ def require_task!
28
+ if project_gid.nil?
29
+ cli.abort 'No current/specified project. Did you initialize Asana and pick a task?'
30
+ end
31
+ cli.abort 'No current/specified task. Did you pick an Asana task?' if task_gid.nil?
32
+ end
33
+
23
34
  def same_args_as_config?
24
35
  project_gid == config.project_gid && task_gid == config.task_gid
25
36
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Asana
6
+ module Commands
7
+ class Add < BaseCommand
8
+ def self.command
9
+ 'add asana[:<project-gid>]'
10
+ end
11
+
12
+ def self.description
13
+ 'Create a new task for the current/specified Asana project'
14
+ end
15
+
16
+ def call
17
+ require_project!
18
+
19
+ task
20
+ print_task(project, task)
21
+
22
+ move_task if section
23
+ end
24
+
25
+ private
26
+
27
+ def task
28
+ @task ||= begin
29
+ body = {
30
+ data: {
31
+ name: name,
32
+ notes: notes,
33
+ projects: [project_gid]
34
+ }
35
+ }
36
+ cli.warn 'Creating task'
37
+ api.post('tasks', Oj.dump(body, mode: :json))
38
+ end
39
+ end
40
+
41
+ def move_task
42
+ body = { data: { task: task['gid'] } }
43
+ body_json = Oj.dump(body, mode: :json)
44
+ api.post("sections/#{section['gid']}/addTask", body_json)
45
+ end
46
+
47
+ def name
48
+ @name ||= cli.prompt 'Enter task description'
49
+ end
50
+
51
+ def notes
52
+ @notes ||= cli.prompt 'Enter task notes'
53
+ end
54
+
55
+ def project
56
+ @project ||= api.get("projects/#{project_gid}")
57
+ end
58
+
59
+ def section
60
+ @section ||= cli.prompt_choice 'Add to section?', sections, ['q', 'Don\'t add to section']
61
+ end
62
+
63
+ def sections
64
+ @sections ||= begin
65
+ cli.warn 'Fetching sections...'
66
+ api.get_paged("projects/#{project_gid}/sections", opt_fields: 'name')
67
+ rescue Abt::HttpError::HttpError
68
+ []
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -14,6 +14,8 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
+ require_project!
18
+
17
19
  if same_args_as_config? || !config.local_available?
18
20
  show_current_configuration
19
21
  else
@@ -25,9 +27,7 @@ module Abt
25
27
  private
26
28
 
27
29
  def show_current_configuration
28
- if project_gid.nil?
29
- cli.warn 'No project selected'
30
- elsif task_gid.nil?
30
+ if task_gid.nil?
31
31
  print_project(project)
32
32
  else
33
33
  print_task(project, task)
@@ -17,7 +17,7 @@ module Abt
17
17
  unless config.local_available?
18
18
  cli.abort 'This is a no-op for tasks outside the current project'
19
19
  end
20
- cli.abort 'No current or specified task' if task.nil?
20
+ require_task!
21
21
  print_task(project_gid, task)
22
22
 
23
23
  if task_already_in_finalized_section?
@@ -14,6 +14,7 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
+ require_task!
17
18
  ensure_current_is_valid!
18
19
 
19
20
  body = {
@@ -15,6 +15,7 @@ module Abt
15
15
 
16
16
  def call
17
17
  cli.abort 'Must be run inside a git repository' unless config.local_available?
18
+ require_project!
18
19
 
19
20
  cli.warn project['name']
20
21
 
@@ -14,9 +14,9 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
- if project_gid.nil?
18
- cli.warn 'No project selected'
19
- elsif task_gid.nil?
17
+ require_project!
18
+
19
+ if task_gid.nil?
20
20
  cli.print_provider_command('asana', project_gid)
21
21
  else
22
22
  cli.print_provider_command('asana', "#{project_gid}/#{task_gid}")
@@ -14,7 +14,7 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
- abort 'No current/provided task' if task_gid.nil?
17
+ require_task!
18
18
 
19
19
  maybe_override_current_task
20
20
 
@@ -14,6 +14,8 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
+ require_project!
18
+
17
19
  tasks.each do |task|
18
20
  print_task(project, task)
19
21
  end
@@ -28,6 +28,18 @@ module Abt
28
28
  # TODO: Loop if necessary
29
29
  end
30
30
 
31
+ def work_item_query(wiql)
32
+ response = post('wit/wiql', Oj.dump({ query: wiql }, mode: :json))
33
+ ids = response['workItems'].map { |work_item| work_item['id'] }
34
+
35
+ work_items = []
36
+ ids.each_slice(200) do |page_ids|
37
+ work_items += get_paged('wit/workitems', ids: page_ids.join(','))
38
+ end
39
+
40
+ work_items
41
+ end
42
+
31
43
  def request(*args)
32
44
  response = connection.public_send(*args)
33
45
 
@@ -21,6 +21,22 @@ module Abt
21
21
 
22
22
  private
23
23
 
24
+ def require_board!
25
+ return if organization_name && project_name && board_id
26
+
27
+ cli.abort 'No current/specified board. Did you initialize DevOps?'
28
+ end
29
+
30
+ def require_work_item!
31
+ unless organization_name && project_name && board_id
32
+ cli.abort 'No current/specified board. Did you initialize DevOps and pick a work item?'
33
+ end
34
+
35
+ return if work_item_id
36
+
37
+ cli.abort 'No current/specified work item. Did you pick a DevOps work item?'
38
+ end
39
+
24
40
  def sanitize_work_item(work_item)
25
41
  return nil if work_item.nil?
26
42
 
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Devops
6
+ module Commands
7
+ class Boards < BaseCommand
8
+ def self.command
9
+ 'boards devops'
10
+ end
11
+
12
+ def self.description
13
+ 'List all boards - useful for piping into grep etc'
14
+ end
15
+
16
+ def call
17
+ cli.abort 'No organization selected. Did you initialize DevOps?' if organization_name.nil?
18
+ cli.abort 'No project selected. Did you initialize DevOps?' if project_name.nil?
19
+
20
+ boards.map do |board|
21
+ print_board(organization_name, project_name, board)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def boards
28
+ @boards ||= api.get_paged('work/boards')
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -14,6 +14,8 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
+ require_board!
18
+
17
19
  if same_args_as_config? || !config.local_available?
18
20
  show_current_configuration
19
21
  else
@@ -25,13 +27,7 @@ module Abt
25
27
  private
26
28
 
27
29
  def show_current_configuration
28
- if organization_name.nil?
29
- cli.warn 'No organization selected'
30
- elsif project_name.nil?
31
- cli.warn 'No project selected'
32
- elsif board_id.nil?
33
- cli.warn 'No board selected'
34
- elsif work_item_id.nil?
30
+ if work_item_id.nil?
35
31
  print_board(organization_name, project_name, board)
36
32
  else
37
33
  print_work_item(organization_name, project_name, board, work_item)
@@ -14,6 +14,8 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
+ require_work_item!
18
+
17
19
  body = {
18
20
  notes: notes,
19
21
  external_reference: {
@@ -15,22 +15,26 @@ module Abt
15
15
 
16
16
  def call
17
17
  cli.abort 'Must be run inside a git repository' unless config.local_available?
18
+ require_board!
18
19
 
19
20
  cli.warn "#{project_name} - #{board['name']}"
20
21
 
21
22
  work_item = select_work_item
22
23
 
23
- # We might have gotten org, project, board as arg str
24
- config.organization_name = organization_name
25
- config.project_name = project_name
26
- config.board_id = board_id
27
- config.work_item_id = work_item['id']
24
+ update_config!(work_item)
28
25
 
29
26
  print_work_item(organization_name, project_name, board, work_item)
30
27
  end
31
28
 
32
29
  private
33
30
 
31
+ def update_config!(work_item)
32
+ config.organization_name = organization_name
33
+ config.project_name = project_name
34
+ config.board_id = board_id
35
+ config.work_item_id = work_item['id']
36
+ end
37
+
34
38
  def select_work_item
35
39
  loop do
36
40
  column = cli.prompt_choice 'Which column?', columns
@@ -48,16 +52,14 @@ module Abt
48
52
  end
49
53
 
50
54
  def work_items_in_column(column)
51
- wiql = <<~WIQL
52
- SELECT [System.Id]
53
- FROM WorkItems
54
- WHERE [System.BoardColumn] = '#{column['name']}'
55
- ORDER BY [Microsoft.VSTS.Common.BacklogPriority] ASC
56
- WIQL
57
-
58
- response = api.post('wit/wiql', Oj.dump({ query: wiql }, mode: :json))
59
- ids = response['workItems'].map { |work_item| work_item['id'] }
60
- work_items = api.get_paged('wit/workitems', ids: ids.join(','))
55
+ work_items = api.work_item_query(
56
+ <<~WIQL
57
+ SELECT [System.Id]
58
+ FROM WorkItems
59
+ WHERE [System.BoardColumn] = '#{column['name']}'
60
+ ORDER BY [Microsoft.VSTS.Common.BacklogPriority] ASC
61
+ WIQL
62
+ )
61
63
 
62
64
  work_items.map { |work_item| sanitize_work_item(work_item) }
63
65
  end
@@ -14,16 +14,10 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
- if organization_name.nil?
18
- cli.warn 'No organization selected'
19
- elsif project_name.nil?
20
- cli.warn 'No project selected'
21
- elsif board_id.nil?
22
- cli.warn 'No board selected'
23
- else
24
- args = [organization_name, project_name, board_id, work_item_id].compact
25
- cli.print_provider_command('devops', args.join('/'))
26
- end
17
+ require_work_item!
18
+
19
+ args = [organization_name, project_name, board_id, work_item_id].compact
20
+ cli.print_provider_command('devops', args.join('/'))
27
21
  end
28
22
  end
29
23
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Abt
4
+ module Providers
5
+ module Devops
6
+ module Commands
7
+ class WorkItems < BaseCommand
8
+ def self.command
9
+ 'work-items devops'
10
+ end
11
+
12
+ def self.description
13
+ 'List all work items on board - useful for piping into grep etc.'
14
+ end
15
+
16
+ def call
17
+ require_board!
18
+
19
+ work_items.each do |work_item|
20
+ print_work_item(organization_name, project_name, board, work_item)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def work_items
27
+ @work_items ||= begin
28
+ cli.warn 'Fetching work items...'
29
+ api.work_item_query(
30
+ <<~WIQL
31
+ SELECT [System.Id]
32
+ FROM WorkItems
33
+ ORDER BY [System.Title] ASC
34
+ WIQL
35
+ ).map { |work_item| sanitize_work_item(work_item) }
36
+ end
37
+ end
38
+
39
+ def board
40
+ @board ||= api.get("work/boards/#{board_id}")
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -20,6 +20,17 @@ module Abt
20
20
 
21
21
  private
22
22
 
23
+ def require_project!
24
+ cli.abort 'No current/specified project. Did you initialize Harvest?' if project_id.nil?
25
+ end
26
+
27
+ def require_task!
28
+ if project_id.nil?
29
+ cli.abort 'No current/specified project. Did you initialize Harvest and pick a task?'
30
+ end
31
+ cli.abort 'No current/specified task. Did you pick a Harvest task?' if task_id.nil?
32
+ end
33
+
23
34
  def same_args_as_config?
24
35
  project_id == config.project_id && task_id == config.task_id
25
36
  end
@@ -14,6 +14,8 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
+ require_project!
18
+
17
19
  if same_args_as_config? || !config.local_available?
18
20
  show_current_configuration
19
21
  else
@@ -25,9 +27,7 @@ module Abt
25
27
  private
26
28
 
27
29
  def show_current_configuration
28
- if project_id.nil?
29
- cli.warn 'No project selected'
30
- elsif task_id.nil?
30
+ if task_id.nil?
31
31
  print_project(project)
32
32
  else
33
33
  print_task(project, task)
@@ -15,6 +15,7 @@ module Abt
15
15
 
16
16
  def call
17
17
  cli.abort 'Must be run inside a git repository' unless config.local_available?
18
+ require_project!
18
19
 
19
20
  cli.warn project['name']
20
21
  task = cli.prompt_choice 'Select a task', tasks
@@ -37,9 +37,7 @@ module Abt
37
37
  output = StringIO.new
38
38
  Abt::Cli.new(argv: ['track'], output: output, input: input).perform
39
39
 
40
- output_str = output.string.strip
41
- cli.abort 'No task provided' if output_str.empty?
42
- output_str
40
+ output.string.strip
43
41
  end
44
42
 
45
43
  def maybe_override_current_task
@@ -14,6 +14,8 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
+ require_project!
18
+
17
19
  tasks.each do |task|
18
20
  print_task(project, task)
19
21
  end
@@ -14,8 +14,7 @@ module Abt
14
14
  end
15
15
 
16
16
  def call
17
- abort 'No current/provided task' if task_id.nil?
18
- cli.abort('No task selected') if task_id.nil?
17
+ require_task!
19
18
 
20
19
  print_task(created_time_entry['project'], created_time_entry['task'])
21
20
 
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.11'
4
+ VERSION = '0.0.12'
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.11
4
+ version: 0.0.12
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-29 00:00:00.000000000 Z
11
+ date: 2021-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-inflector
@@ -88,6 +88,7 @@ files:
88
88
  - "./lib/abt/providers/asana.rb"
89
89
  - "./lib/abt/providers/asana/api.rb"
90
90
  - "./lib/abt/providers/asana/base_command.rb"
91
+ - "./lib/abt/providers/asana/commands/add.rb"
91
92
  - "./lib/abt/providers/asana/commands/clear.rb"
92
93
  - "./lib/abt/providers/asana/commands/clear_global.rb"
93
94
  - "./lib/abt/providers/asana/commands/current.rb"
@@ -103,6 +104,7 @@ files:
103
104
  - "./lib/abt/providers/devops.rb"
104
105
  - "./lib/abt/providers/devops/api.rb"
105
106
  - "./lib/abt/providers/devops/base_command.rb"
107
+ - "./lib/abt/providers/devops/commands/boards.rb"
106
108
  - "./lib/abt/providers/devops/commands/clear.rb"
107
109
  - "./lib/abt/providers/devops/commands/clear_global.rb"
108
110
  - "./lib/abt/providers/devops/commands/current.rb"
@@ -110,6 +112,7 @@ files:
110
112
  - "./lib/abt/providers/devops/commands/init.rb"
111
113
  - "./lib/abt/providers/devops/commands/pick.rb"
112
114
  - "./lib/abt/providers/devops/commands/share.rb"
115
+ - "./lib/abt/providers/devops/commands/work-items.rb"
113
116
  - "./lib/abt/providers/devops/configuration.rb"
114
117
  - "./lib/abt/providers/harvest.rb"
115
118
  - "./lib/abt/providers/harvest/api.rb"