dude-cli 2.0.5 → 2.1.0.alpha3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/verify.yml +32 -0
  3. data/.rspec +0 -1
  4. data/.rubocop.yml +13 -0
  5. data/CHANGELOG.md +7 -3
  6. data/Gemfile +3 -1
  7. data/Gemfile.lock +62 -9
  8. data/LICENCE +20 -0
  9. data/README.md +60 -35
  10. data/Rakefile +5 -3
  11. data/bin/console +4 -3
  12. data/bin/dude +2 -2
  13. data/demo/dude.gif +0 -0
  14. data/demo/wizard.gif +0 -0
  15. data/dude.gemspec +26 -18
  16. data/lib/dude.rb +18 -7
  17. data/lib/dude/code_management.rb +10 -0
  18. data/lib/dude/code_management/github/client.rb +27 -0
  19. data/lib/dude/code_management/github/create_pull_request.rb +51 -0
  20. data/lib/dude/commands.rb +26 -17
  21. data/lib/dude/commands/checkout.rb +4 -2
  22. data/lib/dude/commands/health_check.rb +15 -0
  23. data/lib/dude/commands/install.rb +67 -43
  24. data/lib/dude/commands/move.rb +5 -3
  25. data/lib/dude/commands/pr.rb +11 -0
  26. data/lib/dude/commands/pr/create.rb +49 -0
  27. data/lib/dude/commands/pr/remove.rb +15 -0
  28. data/lib/dude/commands/start.rb +14 -10
  29. data/lib/dude/commands/stop.rb +4 -4
  30. data/lib/dude/commands/tasks.rb +6 -5
  31. data/lib/dude/commands/track.rb +7 -7
  32. data/lib/dude/commands/version.rb +3 -1
  33. data/lib/dude/config.rb +18 -0
  34. data/lib/dude/git.rb +3 -0
  35. data/lib/dude/git/checkout.rb +20 -1
  36. data/lib/dude/git/current_branch_name.rb +3 -1
  37. data/lib/dude/git/remote_name.rb +21 -0
  38. data/lib/dude/health_check.rb +39 -0
  39. data/lib/dude/project_management/client.rb +14 -7
  40. data/lib/dude/project_management/entities/issue.rb +10 -7
  41. data/lib/dude/project_management/jira.rb +2 -1
  42. data/lib/dude/project_management/jira/client.rb +35 -18
  43. data/lib/dude/project_management/jira/fetch_current_task.rb +35 -0
  44. data/lib/dude/project_management/jira/fetch_current_tasks.rb +46 -0
  45. data/lib/dude/project_management/jira/get_task_name_by_id.rb +1 -3
  46. data/lib/dude/project_management/jira/move_task_to_list.rb +15 -15
  47. data/lib/dude/project_management/{entities/board.rb → trello.rb} +3 -4
  48. data/lib/dude/project_management/trello/client.rb +56 -0
  49. data/lib/dude/project_management/trello/fetch_current_task.rb +41 -0
  50. data/lib/dude/project_management/trello/fetch_current_tasks.rb +51 -0
  51. data/lib/dude/project_management/trello/fetch_lists.rb +22 -0
  52. data/lib/dude/project_management/trello/get_task_name_by_id.rb +23 -0
  53. data/lib/dude/project_management/trello/move_task_to_list.rb +53 -0
  54. data/lib/dude/settings.rb +3 -0
  55. data/lib/dude/setup/github.rb +35 -0
  56. data/lib/dude/setup/jira.rb +64 -0
  57. data/lib/dude/setup/toggl.rb +47 -0
  58. data/lib/dude/setup/trello.rb +58 -0
  59. data/lib/dude/templates/duderc_template +32 -0
  60. data/lib/dude/time_trackers/toggl.rb +2 -0
  61. data/lib/dude/time_trackers/toggl/base.rb +4 -4
  62. data/lib/dude/time_trackers/toggl/start_time_entry.rb +3 -2
  63. data/lib/dude/time_trackers/toggl/stop_time_entry.rb +3 -1
  64. data/lib/dude/version.rb +3 -1
  65. metadata +99 -14
  66. data/lib/dude/project_management/jira/get_current_tasks.rb +0 -40
@@ -1,11 +1,9 @@
1
- require 'dude/project_management/jira/client'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Dude
4
4
  module ProjectManagement
5
5
  module Jira
6
6
  class GetTaskNameById
7
- include Settings
8
-
9
7
  def initialize(client, id:)
10
8
  @client = client
11
9
  @id = id
@@ -1,11 +1,9 @@
1
- require 'dude/project_management/jira/client'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Dude
4
4
  module ProjectManagement
5
5
  module Jira
6
6
  class MoveTaskToList
7
- include Settings
8
-
9
7
  def initialize(client, id:, list_name:)
10
8
  @client = client
11
9
  @id = id
@@ -14,33 +12,35 @@ module Dude
14
12
 
15
13
  def call
16
14
  issue = client.Issue.find(id)
17
- available_transitions = client.Transition.all(:issue => issue)
15
+ available_transitions = client.Transition.all(issue: issue)
16
+ transition_id = generate_transition_id(issue, available_transitions)
17
+ transition = issue.transitions.build
18
+ transition.save!(transition: { id: transition_id })
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :client, :id, :list_name
18
24
 
19
- transition_id = if list_name
25
+ def generate_transition_id(issue, available_transitions)
26
+ if list_name
20
27
  available_transitions.find { |transition| transition.name == list_name }.id
21
28
  else
22
29
  select_list_for_moving(issue, available_transitions).id
23
30
  end
24
-
25
- transition = issue.transitions.build
26
- transition.save!(transition: { id: transition_id })
27
31
  end
28
32
 
29
- private
30
-
31
- def select_list_for_moving(issuem, available_transitions)
32
- puts "Please, select list for moving:".green.bold
33
+ def select_list_for_moving(_issue, available_transitions)
34
+ puts 'Please, select list for moving:'.green.bold
33
35
 
34
36
  available_transitions.each_with_index do |ea, index|
35
37
  puts "#{index + 1}: #{ea.name.bold}"
36
38
  end
37
39
 
38
40
  print "\nList index: ".bold
39
- list_index = STDIN.gets.chomp
41
+ list_index = $stdin.gets.chomp
40
42
  available_transitions[list_index.to_i - 1]
41
43
  end
42
-
43
- attr_reader :client, :id, :list_name
44
44
  end
45
45
  end
46
46
  end
@@ -1,9 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module ProjectManagement
3
- module Entities
4
- class Issue
5
-
6
- end
5
+ module Trello
7
6
  end
8
7
  end
9
8
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './fetch_current_tasks'
4
+ require_relative './fetch_current_task'
5
+ require_relative './move_task_to_list'
6
+ require_relative './get_task_name_by_id'
7
+
8
+ require 'faraday'
9
+ require 'json'
10
+
11
+ module Dude
12
+ module ProjectManagement
13
+ module Trello
14
+ class Client
15
+ def client
16
+ @client ||= Faraday.new('https://api.trello.com/', {
17
+ params: {
18
+ key: Dude::SETTINGS.dig(:trello, :key),
19
+ token: Dude::SETTINGS.dig(:trello, :token)
20
+ }
21
+ })
22
+ end
23
+
24
+ def method_missing(method, *args, &block)
25
+ faraday_client.send(method, *args, &block)
26
+ end
27
+
28
+ def respond_to_missing?(method_name, include_private = false)
29
+ client.respond_to?(method_name, include_private)
30
+ end
31
+
32
+ def fetch_current_tasks
33
+ FetchCurrentTasks.new(client).call
34
+ end
35
+
36
+ def fetch_current_task(id)
37
+ FetchCurrentTask.new(client, id: id).call
38
+ end
39
+
40
+ def move_task_to_list(id, list)
41
+ MoveTaskToList.new(client, id: id, list_name: list).call
42
+ end
43
+
44
+ def get_task_name_by_id(id)
45
+ GetTaskNameById.new(client, id: id).call
46
+ end
47
+
48
+ def health_check
49
+ client.get("/1/tokens/#{Dude::SETTINGS.dig(:trello, :token)}").status == 200
50
+ rescue StandardError
51
+ false
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ module ProjectManagement
5
+ module Trello
6
+ class FetchCurrentTask
7
+ def initialize(client, id:)
8
+ @client = client
9
+ @id = id
10
+ end
11
+
12
+ def call
13
+ response = client.get("/1/boards/#{Dude::SETTINGS.dig(:jira, :board_id)}/cards/#{id}")
14
+ create_issue JSON.parse(response.body)
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :client, :id
20
+
21
+ def create_issue(issue)
22
+ Entities::Issue.new(
23
+ id: issue['idShort'],
24
+ title: issue['name'],
25
+ description: issue['desc'],
26
+ status: Dude::SETTINGS[:in_progress_list_name], # OMG, let's fix this later
27
+ assignee: members(issue),
28
+ url: issue['shortUrl']
29
+ )
30
+ end
31
+
32
+ def members(issue)
33
+ people = issue['idMembers'].map do |person|
34
+ JSON.parse(client.get("/1/members/#{person}", fields: 'fullName').body)['fullName']
35
+ end
36
+ people.empty? ? nil : people.join(', ')
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './fetch_lists'
4
+
5
+ module Dude
6
+ module ProjectManagement
7
+ module Trello
8
+ class FetchCurrentTasks
9
+ attr_reader :fetch_lists
10
+
11
+ def initialize(client, fetch_lists: nil)
12
+ @client = client
13
+
14
+ @fetch_lists = fetch_lists || FetchLists.new(client)
15
+ end
16
+
17
+ def call
18
+ lists = fetch_lists.call
19
+ lists.map { |list| retrieve_list_issues(list) }.flatten
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :client
25
+
26
+ def retrieve_list_issues(list)
27
+ response = client.get("/1/lists/#{list['id']}/cards")
28
+ body = JSON.parse(response.body)
29
+ body.map { |issue| create_issue(issue, list) }
30
+ end
31
+
32
+ def create_issue(issue, current_list)
33
+ Entities::Issue.new(
34
+ id: issue['idShort'],
35
+ title: issue['name'],
36
+ description: issue['desc'],
37
+ status: current_list['name'],
38
+ assignee: members(issue)
39
+ )
40
+ end
41
+
42
+ def members(issue)
43
+ people = issue['idMembers'].map do |person|
44
+ JSON.parse(client.get("/1/members/#{person}", fields: 'fullName').body)['fullName']
45
+ end
46
+ people.empty? ? nil : people.join(', ')
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ module ProjectManagement
5
+ module Trello
6
+ class FetchLists
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def call
12
+ response = client.get("/1/board/#{Dude::SETTINGS.dig(:jira, :board_id)}/lists", { fields: 'name' })
13
+ JSON.parse(response.body)
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :client
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ module ProjectManagement
5
+ module Trello
6
+ class GetTaskNameById
7
+ def initialize(client, id:)
8
+ @client = client
9
+ @id = id
10
+ end
11
+
12
+ def call
13
+ response = client.get("/1/boards/#{Dude::SETTINGS.dig(:jira, :board_id)}/cards/#{id}")
14
+ JSON.parse(response.body)['name']
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :client, :id
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './fetch_lists'
4
+
5
+ module Dude
6
+ module ProjectManagement
7
+ module Trello
8
+ class MoveTaskToList
9
+ def initialize(client, id:, list_name:)
10
+ @client = client
11
+ @id = id
12
+ @list_name = list_name
13
+ end
14
+
15
+ def call
16
+ response = client.get("/1/boards/#{Dude::SETTINGS.dig(:jira, :board_id)}/cards/#{id}", { fields: 'id' })
17
+ card_id = JSON.parse(response.body)['id']
18
+ client.put("/1/cards/#{card_id}", { idList: list_id })
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :client, :id, :list_name
24
+
25
+ def list_id
26
+ if list_name
27
+ lists.find { |list| list['name'] == list_name }['id']
28
+ else
29
+ select_list_for_moving['id']
30
+ end
31
+ end
32
+
33
+ def select_list_for_moving
34
+ puts 'Please, select list for moving:'.green.bold
35
+
36
+ print_lists
37
+
38
+ print "\nList index: ".bold
39
+ list_index = $stdin.gets.chomp
40
+ lists[list_index.to_i - 1]
41
+ end
42
+
43
+ def print_lists
44
+ lists.map { |list| list['name'] }.each_with_index { |name, index| puts "#{index + 1}: #{name.bold}" }
45
+ end
46
+
47
+ def lists
48
+ @lists ||= FetchLists.new(client).call
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
data/lib/dude/settings.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module Settings
3
5
  CONFIG_FILE = '.duderc'
@@ -5,6 +7,7 @@ module Dude
5
7
  def settings
6
8
  @settings ||= read(file).strip.split("\n").map do |line|
7
9
  next if line =~ /^#/ || line.empty?
10
+
8
11
  line.split('=').map(&:strip)
9
12
  end.compact.to_h
10
13
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ module Setup
5
+ class Github
6
+ def initialize(prompt)
7
+ @prompt = prompt
8
+ end
9
+
10
+ def call(settings:)
11
+ settings[:github][:token] = setup_token
12
+ settings
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :prompt
18
+
19
+ def setup_token
20
+ puts <<~HEREDOC
21
+ You need to create personal token
22
+
23
+ #{'1.'.bold} Log in to https://github.com/settings/tokens
24
+ #{'2.'.bold} Copy the token and paste it below
25
+ HEREDOC
26
+
27
+ if prompt.yes?(Dude::Config.style_prompt('Open Github token creation page in your browser?'))
28
+ `open https://github.com/settings/tokens`
29
+ end
30
+
31
+ prompt.ask(Dude::Config.style_prompt('Github token:'), required: true)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ module Setup
5
+ class Jira
6
+ def initialize(prompt)
7
+ @prompt = prompt
8
+ end
9
+
10
+ # rubocop:disable Metrics/AbcSize
11
+ def call(settings:)
12
+ settings[:jira][:email] = setup_email
13
+ settings[:jira][:token] = setup_token
14
+ settings[:jira][:project][:url] = setup_project_url
15
+ settings[:jira][:project][:key] = setup_project_key
16
+ settings[:jira][:board_id] = setup_board_id
17
+ settings
18
+ end
19
+ # rubocop:enable Metrics/AbcSize
20
+
21
+ private
22
+
23
+ attr_reader :prompt
24
+
25
+ def setup_email
26
+ prompt.ask(Dude::Config.style_prompt('Jira user email:'), required: true)
27
+ end
28
+
29
+ def setup_token
30
+ puts <<~HEREDOC
31
+ You need to create personal token
32
+
33
+ #{'1.'.bold} Log in to https://id.atlassian.com/manage/api-tokens
34
+ #{'2.'.bold} Click 'Create API token.'
35
+ #{'3.'.bold} From the dialog that appears, enter a memorable and concise 'Label' for your token and click 'Create.'
36
+ #{'4.'.bold} Use 'Copy to clipboard' and paste the token below
37
+ HEREDOC
38
+
39
+ if prompt.yes?(Dude::Config.style_prompt('Open Atlassian token creation page in your browser?'))
40
+ `open https://id.atlassian.com/manage-profile/security/api-tokens`
41
+ end
42
+
43
+ prompt.ask(Dude::Config.style_prompt('Jira token:'), required: true)
44
+ end
45
+
46
+ def setup_project_url
47
+ prompt.ask(Dude::Config.style_prompt('URL of your project (Example: https://example.atlassian.net):'), {
48
+ required: true
49
+ })
50
+ end
51
+
52
+ def setup_project_key
53
+ prompt.ask(Dude::Config.style_prompt('KEY of your project (If your issues have id BT-123 - BT is the key):'), {
54
+ required: true
55
+ })
56
+ end
57
+
58
+ def setup_board_id
59
+ puts 'Just open your atlassian main board and copy id from the url after rapidView=ID part.'
60
+ prompt.ask(Dude::Config.style_prompt('Board ID:'), required: true)
61
+ end
62
+ end
63
+ end
64
+ end