dude-cli 2.0.7 → 2.1.0.alpha5

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rubocop.yml +5 -1
  4. data/Gemfile.lock +36 -15
  5. data/README.md +43 -35
  6. data/dude.gemspec +3 -2
  7. data/lib/dude.rb +12 -2
  8. data/lib/dude/code_management.rb +10 -0
  9. data/lib/dude/code_management/github/client.rb +27 -0
  10. data/lib/dude/code_management/github/create_pull_request.rb +61 -0
  11. data/lib/dude/commands.rb +7 -0
  12. data/lib/dude/commands/health_check.rb +15 -0
  13. data/lib/dude/commands/install.rb +63 -41
  14. data/lib/dude/commands/pr.rb +11 -0
  15. data/lib/dude/commands/pr/create.rb +49 -0
  16. data/lib/dude/commands/pr/remove.rb +15 -0
  17. data/lib/dude/commands/start.rb +10 -8
  18. data/lib/dude/commands/stop.rb +0 -2
  19. data/lib/dude/commands/tasks.rb +0 -2
  20. data/lib/dude/commands/track.rb +2 -4
  21. data/lib/dude/config.rb +18 -0
  22. data/lib/dude/git.rb +1 -0
  23. data/lib/dude/git/remote_name.rb +21 -0
  24. data/lib/dude/health_check.rb +39 -0
  25. data/lib/dude/project_management/client.rb +8 -4
  26. data/lib/dude/project_management/entities/issue.rb +8 -7
  27. data/lib/dude/project_management/jira/client.rb +21 -8
  28. data/lib/dude/project_management/jira/fetch_current_task.rb +37 -0
  29. data/lib/dude/project_management/jira/fetch_current_tasks.rb +3 -4
  30. data/lib/dude/project_management/jira/get_task_name_by_id.rb +0 -2
  31. data/lib/dude/project_management/jira/move_task_to_list.rb +0 -2
  32. data/lib/dude/project_management/{entities/board.rb → trello.rb} +1 -3
  33. data/lib/dude/project_management/trello/client.rb +56 -0
  34. data/lib/dude/project_management/trello/fetch_current_task.rb +41 -0
  35. data/lib/dude/project_management/trello/fetch_current_tasks.rb +51 -0
  36. data/lib/dude/project_management/trello/fetch_lists.rb +22 -0
  37. data/lib/dude/project_management/trello/get_task_name_by_id.rb +23 -0
  38. data/lib/dude/project_management/trello/move_task_to_list.rb +53 -0
  39. data/lib/dude/setup/github.rb +35 -0
  40. data/lib/dude/setup/jira.rb +64 -0
  41. data/lib/dude/setup/toggl.rb +47 -0
  42. data/lib/dude/setup/trello.rb +58 -0
  43. data/lib/dude/templates/duderc_template +32 -0
  44. data/lib/dude/time_trackers/toggl/base.rb +2 -4
  45. data/lib/dude/version.rb +1 -1
  46. metadata +42 -6
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../entities/issue'
4
+
5
+ module Dude
6
+ module ProjectManagement
7
+ module Jira
8
+ class FetchCurrentTask
9
+ def initialize(client, id:)
10
+ @client = client
11
+ @id = id
12
+ end
13
+
14
+ def call
15
+ create_issue(client.Issue.find(id))
16
+ rescue JIRA::HTTPError
17
+ puts "#{'Error:'.red.bold} Task #{id.bold} not found. Try again with correct task ID"
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :client, :id
23
+
24
+ def create_issue(issue)
25
+ Entities::Issue.new(
26
+ id: issue.key,
27
+ title: issue.summary,
28
+ description: issue.description,
29
+ status: issue.status.name,
30
+ assignee: issue&.assignee&.displayName,
31
+ url: "#{Dude::SETTINGS.dig(:dig, :project, :url)}/browse/#{issue.key}"
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -6,14 +6,12 @@ module Dude
6
6
  module ProjectManagement
7
7
  module Jira
8
8
  class FetchCurrentTasks
9
- include Settings
10
-
11
9
  def initialize(client)
12
10
  @client = client
13
11
  end
14
12
 
15
13
  def call
16
- board = client.Board.find(settings['ATLASSIAN_BOARD_ID'])
14
+ board = client.Board.find(Dude::SETTINGS.dig(:jira, :board_id))
17
15
 
18
16
  all_issues = board_type(board)
19
17
 
@@ -38,7 +36,8 @@ module Dude
38
36
  title: issue.summary,
39
37
  description: issue.description,
40
38
  status: issue.status.name,
41
- assignee: issue&.assignee&.displayName
39
+ assignee: issue&.assignee&.displayName,
40
+ url: "#{Dude::SETTINGS.dig(:jira, :project, :url)}/browse/#{issue.key}"
42
41
  )
43
42
  end
44
43
  end
@@ -4,8 +4,6 @@ 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
@@ -4,8 +4,6 @@ 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
@@ -2,9 +2,7 @@
2
2
 
3
3
  module Dude
4
4
  module ProjectManagement
5
- module Entities
6
- class Issue
7
- end
5
+ module Trello
8
6
  end
9
7
  end
10
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
@@ -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