dude-cli 2.0.5 → 2.1.0.alpha3

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 (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,11 @@
1
- require 'dude/time_trackers/toggl/stop_time_entry'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../time_trackers/toggl/stop_time_entry'
2
4
 
3
5
  module Dude
4
6
  module Commands
5
7
  class Stop < Dry::CLI::Command
6
- include Settings
7
-
8
- desc "Stop current time entry in Toggl"
8
+ desc 'Stop current time entry in Toggl'
9
9
 
10
10
  def call
11
11
  Dude::Toggl::StopTimeEntry.new.call
@@ -1,15 +1,15 @@
1
- require 'dude/project_management/client'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../project_management/client'
2
4
 
3
5
  module Dude
4
6
  module Commands
5
7
  class Tasks < Dry::CLI::Command
6
- include Settings
7
-
8
8
  desc "Print tasks as list with ID's and assignees"
9
9
 
10
10
  def call
11
- tasks = Dude::ProjectManagement::Client.new.get_current_tasks
12
- lists = tasks.map {|issue| issue.status}.uniq
11
+ tasks = Dude::ProjectManagement::Client.new.fetch_current_tasks
12
+ lists = tasks.map(&:status).uniq
13
13
 
14
14
  lists.each do |list|
15
15
  puts "#{list}:".green.bold
@@ -24,6 +24,7 @@ module Dude
24
24
 
25
25
  def printable_issue_template(issue)
26
26
  return "#{issue.id.to_s.bold}: #{issue.title}" + " (#{issue.assignee})".blue if issue.assignee
27
+
27
28
  "#{issue.id.to_s.bold}: #{issue.title}"
28
29
  end
29
30
  end
@@ -1,17 +1,17 @@
1
- require 'dude/time_trackers/toggl/start_time_entry'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../time_trackers/toggl/start_time_entry'
2
4
 
3
5
  module Dude
4
6
  module Commands
5
7
  class Track < Dry::CLI::Command
6
- include Settings
7
-
8
- desc "Start time entry in Toggl with issue title and id"
8
+ desc 'Start time entry in Toggl with issue title and id'
9
9
 
10
- argument :id, required: true, desc: "The card short ID"
10
+ argument :id, required: true, desc: 'The card short ID'
11
11
 
12
12
  def call(id:)
13
13
  @id = id
14
- Dude::Toggl::StartTimeEntry.new.call(task_title: task_title, project: settings['TOGGL_PROJECT_NAME'])
14
+ Dude::Toggl::StartTimeEntry.new.call(task_title: task_title, project: Dude::SETTINGS.dig(:toggl, :project_name))
15
15
  end
16
16
 
17
17
  private
@@ -21,7 +21,7 @@ module Dude
21
21
  def task_title
22
22
  client = ProjectManagement::Client.new
23
23
  issue_title = client.get_task_name_by_id(id)
24
- settings['TOGGL_TASK_FORMAT'].sub(/id/, id).sub(/title/, issue_title)
24
+ Dude::SETTINGS.dig(:toggl, :task_format).sub(/{issue_id}/, id).sub(/{issue_title}/, issue_title)
25
25
  end
26
26
  end
27
27
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module Commands
3
5
  class Version < Dry::CLI::Command
4
- desc "Print version"
6
+ desc 'Print version'
5
7
 
6
8
  def call
7
9
  puts Dude::VERSION
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ class Config
5
+ FILE_NAME = '.duderc.yml'
6
+
7
+ # Configure through yaml file
8
+ def self.configure_with(path_to_yaml_file)
9
+ YAML.safe_load(IO.read(path_to_yaml_file), [Symbol])
10
+ rescue StandardError
11
+ {}
12
+ end
13
+
14
+ def self.style_prompt(text)
15
+ "#{'=>'.green.bold} #{text}"
16
+ end
17
+ end
18
+ end
data/lib/dude/git.rb CHANGED
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative './git/checkout'
2
4
  require_relative './git/current_branch_name'
5
+ require_relative './git/remote_name'
3
6
 
4
7
  module Git
5
8
  end
@@ -1,8 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module Git
3
5
  class Checkout
4
6
  def call(branch_name)
5
- %x(git checkout -b #{branch_name})
7
+ @branch_name = branch_name
8
+ branch_exists? ? checkout_on_exising_branch : checkout_and_create
9
+ end
10
+
11
+ private
12
+
13
+ attr_reader :branch_name
14
+
15
+ def branch_exists?
16
+ !`git show-ref refs/heads/#{branch_name}`.empty?
17
+ end
18
+
19
+ def checkout_and_create
20
+ `git checkout -b #{branch_name}`
21
+ end
22
+
23
+ def checkout_on_exising_branch
24
+ `git checkout #{branch_name}`
6
25
  end
7
26
  end
8
27
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module Git
3
5
  class CurrentBranchName
4
6
  def call
5
- %x(git rev-parse --abbrev-ref HEAD).chomp
7
+ `git rev-parse --abbrev-ref HEAD`.chomp
6
8
  end
7
9
  end
8
10
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ module Git
5
+ class RemoteName
6
+ def call
7
+ extract_name push_url
8
+ end
9
+
10
+ private
11
+
12
+ def push_url
13
+ `git remote show origin`.split("\n")[1]
14
+ end
15
+
16
+ def extract_name(url)
17
+ url.scan(%r{(?<=github\.com[/:])(.*)(?=\.git)})[0][0]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './project_management/jira/client'
4
+ require_relative './project_management/trello/client'
5
+
6
+ module Dude
7
+ class HealthCheck
8
+ def call
9
+ validate(:jira, enabled: Dude::SETTINGS.dig(:jira, :token)) do
10
+ Dude::ProjectManagement::Jira::Client.new.health_check
11
+ end
12
+
13
+ validate(:trello, enabled: Dude::SETTINGS.dig(:trello, :token)) do
14
+ Dude::ProjectManagement::Trello::Client.new.health_check
15
+ end
16
+
17
+ validate(:github, enabled: Dude::SETTINGS.dig(:github, :token)) do
18
+ Dude::CodeManagement::Github::Client.new.health_check
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def validate(check, enabled:)
25
+ prepare_validation(check)
26
+ end_validation(check, enabled ? yield : nil, enabled: enabled)
27
+ end
28
+
29
+ def prepare_validation(check)
30
+ print "#{check.capitalize} status: [#{'WAIT'.yellow}]\r"
31
+ end
32
+
33
+ def end_validation(check, status, enabled: false)
34
+ return puts "#{check.capitalize} status: [#{'DISABLED'.blue}] " unless enabled
35
+
36
+ puts "#{check.capitalize} status: [#{status ? 'OK'.green : 'FAILURE'.red}] "
37
+ end
38
+ end
39
+ end
@@ -1,23 +1,30 @@
1
- require 'dude/project_management/jira/client'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './jira/client'
4
+ require_relative './trello/client'
2
5
 
3
6
  module Dude
4
7
  module ProjectManagement
5
8
  class Client
6
- include Settings
7
-
8
9
  attr_reader :client
9
10
 
10
11
  def initialize
11
- return unless LIST_OF_AVAILABLE_PROJECT_MANAGEMENT_TOOLS.include? settings['PROJECT_MANAGEMENT_TOOL']
12
- @client = Dude::ProjectManagement::Jira::Client.new
12
+ tool = Dude::SETTINGS[:project_management_tool]
13
+ return unless LIST_OF_AVAILABLE_PROJECT_MANAGEMENT_TOOLS.include? tool
14
+
15
+ @client = setup_client(tool)
13
16
  end
14
17
 
15
18
  def respond_to_missing?(method_name, include_private = false)
16
19
  client.respond_to_missing?(method_name, include_private)
17
20
  end
18
21
 
19
- def method_missing(m, *args, &block)
20
- client.send(m, *args, &block)
22
+ def method_missing(method, *args, &block)
23
+ client.send(method, *args, &block)
24
+ end
25
+
26
+ def setup_client(tool)
27
+ Object.const_get("Dude::ProjectManagement::#{tool.capitalize}::Client").new
21
28
  end
22
29
  end
23
30
  end
@@ -1,15 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module ProjectManagement
3
5
  module Entities
4
6
  class Issue
5
- attr_accessor :id, :title, :description, :status, :assignee
7
+ attr_accessor :id, :title, :description, :status, :assignee, :url
6
8
 
7
- def initialize(id: , title:, description:, status:, assignee: nil)
8
- @id = id
9
- @title = title
10
- @description = description
11
- @status = status
12
- @assignee = assignee
9
+ def initialize(params)
10
+ @id = params[:id]
11
+ @title = params[:title]
12
+ @description = params[:description]
13
+ @status = params[:status]
14
+ @assignee = params[:assignee]
15
+ @url = params[:url]
13
16
  end
14
17
 
15
18
  def todo?
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dude/project_management/jira/client'
2
4
 
3
5
  module Dude
4
6
  module ProjectManagement
5
7
  module Jira
6
-
7
8
  end
8
9
  end
9
10
  end
@@ -1,39 +1,50 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'jira-ruby'
2
- require 'dude/project_management/jira/get_current_tasks'
3
- require 'dude/project_management/jira/move_task_to_list'
4
- require 'dude/project_management/jira/get_task_name_by_id'
4
+ require_relative './fetch_current_tasks'
5
+ require_relative './fetch_current_task'
6
+ require_relative './move_task_to_list'
7
+ require_relative './get_task_name_by_id'
5
8
 
6
9
  module Dude
7
10
  module ProjectManagement
8
11
  module Jira
9
12
  class Client
10
- include Settings
11
-
12
13
  attr_reader :client, :project
13
14
 
14
- def initialize
15
- options = {
16
- username: settings['ATLASSIAN_EMAIL'],
17
- password: settings['ATLASSIAN_TOKEN'],
18
- site: settings['ATLASSIAN_URL'],
19
- context_path: '',
20
- auth_type: :basic
21
- }
15
+ class << self
16
+ def options
17
+ {
18
+ username: Dude::SETTINGS.dig(:jira, :email),
19
+ password: Dude::SETTINGS.dig(:jira, :token),
20
+ site: Dude::SETTINGS.dig(:jira, :project, :url),
21
+ context_path: '',
22
+ auth_type: :basic
23
+ }
24
+ end
25
+ end
22
26
 
27
+ def initialize
23
28
  @client = JIRA::Client.new(options)
24
- @project = client.Project.find(settings['ATLASSIAN_PROJECT_KEY'])
29
+ @project = client.Project.find(Dude::SETTINGS.dig(:jira, :project, :key))
30
+ rescue StandardError
31
+ nil
25
32
  end
26
33
 
27
34
  def respond_to_missing?(method_name, include_private = false)
28
35
  client.respond_to_missing?(method_name, include_private)
29
36
  end
30
37
 
31
- def method_missing(m, *args, &block)
32
- client.send(m, *args, &block)
38
+ def method_missing(method, *args, &block)
39
+ client.send(method, *args, &block)
33
40
  end
34
41
 
35
- def get_current_tasks
36
- GetCurrentTasks.new(client).call
42
+ def fetch_current_tasks
43
+ FetchCurrentTasks.new(client).call
44
+ end
45
+
46
+ def fetch_current_task(id)
47
+ FetchCurrentTask.new(client, id: id).call
37
48
  end
38
49
 
39
50
  def move_task_to_list(id, list)
@@ -43,6 +54,12 @@ module Dude
43
54
  def get_task_name_by_id(id)
44
55
  GetTaskNameById.new(client, id: id).call
45
56
  end
57
+
58
+ def health_check
59
+ @project && true
60
+ rescue StandardError
61
+ false
62
+ end
46
63
  end
47
64
  end
48
65
  end
@@ -0,0 +1,35 @@
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
+ end
17
+
18
+ private
19
+
20
+ attr_reader :client, :id
21
+
22
+ def create_issue(issue)
23
+ Entities::Issue.new(
24
+ id: issue.key,
25
+ title: issue.summary,
26
+ description: issue.description,
27
+ status: issue.status.name,
28
+ assignee: issue&.assignee&.displayName,
29
+ url: "#{Dude::SETTINGS.dig(:dig, :project, :url)}/browse/#{issue.key}"
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../entities/issue'
4
+
5
+ module Dude
6
+ module ProjectManagement
7
+ module Jira
8
+ class FetchCurrentTasks
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+
13
+ def call
14
+ board = client.Board.find(Dude::SETTINGS.dig(:jira, :board_id))
15
+
16
+ all_issues = board_type(board)
17
+
18
+ all_issues.map { |issue| create_issue(issue) }
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :client
24
+
25
+ def board_type(board)
26
+ case board.type
27
+ when 'kanban' then board.issues
28
+ when 'simple', 'scrum' then board.sprints(state: 'active').flat_map(&:issues)
29
+ else raise Dude::ToBeImplementedError
30
+ end
31
+ end
32
+
33
+ def create_issue(issue)
34
+ Entities::Issue.new(
35
+ id: issue.key,
36
+ title: issue.summary,
37
+ description: issue.description,
38
+ status: issue.status.name,
39
+ assignee: issue&.assignee&.displayName,
40
+ url: "#{Dude::SETTINGS.dig(:jira, :project, :url)}/browse/#{issue.key}"
41
+ )
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end