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,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