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
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tty-prompt'
4
+ require 'fileutils'
5
+
3
6
  require_relative '../settings'
7
+ require_relative '../setup/jira'
8
+ require_relative '../setup/trello'
9
+ require_relative '../setup/toggl'
10
+ require_relative '../setup/github'
4
11
 
5
12
  module Dude
6
13
  module Commands
@@ -8,51 +15,66 @@ module Dude
8
15
  desc 'Creates .duderc for future configuration'
9
16
 
10
17
  def call
11
- path = File.join(Dir.home, Settings::CONFIG_FILE)
12
- if File.exist?(path)
13
- puts 'Config file already exists'
14
- else
15
- File.open(path, 'w') { |f| f.write(duderc_file_content) }
16
- puts '.duderc created in your HOME directory'
17
- end
18
+ @prompt = TTY::Prompt.new
19
+
20
+ create_file_if_not_exists
21
+
22
+ @current_settings = Dude::Config.configure_with('.duderc.yml')
23
+ @current_settings[:project_management_tool] = setup_project_management_tool # jira, trello
24
+ @current_settings = send("setup_#{current_settings[:project_management_tool]}")
25
+ setup_features.each { send("setup_#{_1}") } # toggl, github
26
+
27
+ save
18
28
  end
19
29
 
20
30
  private
21
31
 
22
- def duderc_file_content
23
- <<~HEREDOC
24
- # Please, don't use quotes and spaces.
25
- # Write all variables using following format: NAME=VALUE
26
- #
27
- # Now jira only (Github, Gitlab, Trello later)
28
- PROJECT_MANAGEMENT_TOOL=jira
29
- ATLASSIAN_EMAIL=
30
- # How to create Atlassian token: https://support.siteimprove.com/hc/en-gb/articles/360004317332-How-to-create-an-API-token-from-your-Atlassian-account
31
- ATLASSIAN_TOKEN=
32
- # URL of your project. Example: https://example.atlassian.net
33
- ATLASSIAN_URL=
34
- # KEY of your project. If your issues have id BT-123 - BT is the key
35
- ATLASSIAN_PROJECT_KEY=
36
- # Just open your atlassian main board and copy id from the url after rapidView=*ID* part.
37
- # Example: https://dealmakerns.atlassian.net/secure/RapidBoard.jspa?rapidView=23&projectKey=DT - 23 is the id
38
- ATLASSIAN_BOARD_ID=
39
-
40
- # Replace it with your project list names. Skip for empty lists
41
- TODO_LIST_NAME=To Do
42
- IN_PROGRESS_LIST_NAME=In Progress
43
- CODE_REVIEW_LIST_NAME=Code Review
44
- TESTING_LIST_NAME=TESTABLE
45
- DONE_LIST_NAME=Done
46
-
47
- # Your Toggl project name
48
- TOGGL_PROJECT_NAME=
49
- # Your Toggl API token can be found at the bottom of the page: https://track.toggl.com/profile
50
- TOGGL_TOKEN=
51
- # Can be copied from url here: https://toggl.com/app/projects/. Example: 123456
52
- TOGGL_WORKSPACE_ID=
53
- # Use the *id* and *title* and specify format for the task titles in Trello or keep it as it is
54
- TOGGL_TASK_FORMAT=[id] title
55
- HEREDOC
32
+ attr_reader :prompt, :current_settings
33
+
34
+ def setup_project_management_tool
35
+ prompt.select(Dude::Config.style_prompt("Select project management tool you're going to use:")) do |menu|
36
+ menu.choice name: 'Jira', value: 'jira'
37
+ menu.choice name: 'Trello', value: 'trello'
38
+ menu.choice name: 'Pivotal Tracker', value: 'pivotal', disabled: '(coming in future)'
39
+ menu.choice name: 'Github', value: 'github', disabled: '(coming in future)'
40
+ end
41
+ end
42
+
43
+ def method_missing(method, *args, &block)
44
+ return super unless method.start_with?('setup_')
45
+
46
+ const_name = method.to_s.split('setup_').last
47
+ Object.const_get("Dude::Setup::#{const_name.capitalize}").new(prompt).call(settings: current_settings)
48
+ end
49
+
50
+ def respond_to_missing?(method_name, include_private = false)
51
+ client.respond_to_missing?(method_name, include_private)
52
+ end
53
+
54
+ def setup_features
55
+ prompt.multi_select(Dude::Config.style_prompt('Select features you want to use:')) do |menu|
56
+ menu.choice 'Toggl time tracking features (Create/stop time entries)', :toggl
57
+ menu.choice 'Github PR creation', :github
58
+ end
59
+ end
60
+
61
+ def save
62
+ File.open('.duderc.yml', 'w') { |file| file.write(current_settings.to_yaml) }
63
+ puts 'Configuration file has been sucessfully updated'.green.bold
64
+ puts 'Your settings are in the .duderc.yml file'.yellow
65
+ puts 'You could change it manually for editing Toggl task format and Github PR template'.yellow
66
+ rescue StandardError => e
67
+ puts "Something went wrong: #{e}"
68
+ end
69
+
70
+ def create_file_if_not_exists
71
+ path = File.join(Dir.pwd, Config::FILE_NAME)
72
+ if File.exist?(path)
73
+ puts 'Config file already exists. All settings will be rewrited'
74
+ else
75
+ FileUtils.cp(File.join(File.dirname(__FILE__), '../templates/duderc_template'), path)
76
+ puts '.duderc created in your HOME directory'
77
+ end
56
78
  end
57
79
  end
58
80
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './pr/create'
4
+ require_relative './pr/remove'
5
+
6
+ module Dude
7
+ module Commands
8
+ module PR
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ module Commands
5
+ module PR
6
+ BASE_BRANCH = 'master'
7
+
8
+ class Create < Dry::CLI::Command
9
+ desc 'Create PR with custom template description'
10
+
11
+ argument :id, required: true, desc: 'The card short ID'
12
+
13
+ def call(id:)
14
+ @id = id
15
+ client = CodeManagement::Github::Client.new
16
+ client.create_pull_request(issue: issue, owner: owner, repo: repo, params: params)
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :id
22
+
23
+ def owner
24
+ repository_name.split('/')[0]
25
+ end
26
+
27
+ def issue
28
+ client = ProjectManagement::Client.new
29
+ client.fetch_current_task(id)
30
+ end
31
+
32
+ def repo
33
+ repository_name.split('/')[1]
34
+ end
35
+
36
+ def params
37
+ {
38
+ head: Git::CurrentBranchName.new.call,
39
+ base: BASE_BRANCH
40
+ }
41
+ end
42
+
43
+ def repository_name
44
+ @repository_name ||= Git::RemoteName.new.call
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dude
4
+ module Commands
5
+ module PR
6
+ class Remove < Dry::CLI::Command
7
+ desc 'Remove'
8
+
9
+ def call(*)
10
+ puts 'To be created later'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -3,8 +3,6 @@
3
3
  module Dude
4
4
  module Commands
5
5
  class Start < Dry::CLI::Command
6
- include Settings
7
-
8
6
  desc 'Start task (Do checkout, track and move actions)'
9
7
 
10
8
  argument :id, required: true, desc: 'The card short ID'
@@ -12,20 +10,24 @@ module Dude
12
10
  def call(id:)
13
11
  Commands::Move.new.call(id: id, list: selected_list('in_progress'))
14
12
  Commands::Checkout.new.call(id: id)
15
- Commands::Track.new.call(id: id)
13
+ Commands::Track.new.call(id: id) if time_tracking_enabled?
16
14
  end
17
15
 
18
16
  private
19
17
 
20
18
  def selected_list(list)
21
19
  case list
22
- when 'todo' then settings['TODO_LIST_NAME']
23
- when 'in_progress' then settings['IN_PROGRESS_LIST_NAME']
24
- when 'code_review' then settings['CODE_REVIEW_LIST_NAME']
25
- when 'testing' then settings['TESTING_LIST_NAME']
26
- when 'done' then settings['DONE_LIST_NAME']
20
+ when 'todo' then Dude::SETTINGS[:todo_list_name]
21
+ when 'in_progress' then Dude::SETTINGS[:in_progress_list_name]
22
+ when 'code_review' then Dude::SETTINGS[:code_review_list_name]
23
+ when 'testing' then Dude::SETTINGS[:testing_list_name]
24
+ when 'done' then Dude::SETTINGS[:done_list_name]
27
25
  end
28
26
  end
27
+
28
+ def time_tracking_enabled?
29
+ !Dude::SETTINGS.dig(:toggl, :token).nil?
30
+ end
29
31
  end
30
32
  end
31
33
  end
@@ -5,8 +5,6 @@ require_relative '../time_trackers/toggl/stop_time_entry'
5
5
  module Dude
6
6
  module Commands
7
7
  class Stop < Dry::CLI::Command
8
- include Settings
9
-
10
8
  desc 'Stop current time entry in Toggl'
11
9
 
12
10
  def call
@@ -5,8 +5,6 @@ require_relative '../project_management/client'
5
5
  module Dude
6
6
  module Commands
7
7
  class Tasks < Dry::CLI::Command
8
- include Settings
9
-
10
8
  desc "Print tasks as list with ID's and assignees"
11
9
 
12
10
  def call
@@ -5,15 +5,13 @@ require_relative '../time_trackers/toggl/start_time_entry'
5
5
  module Dude
6
6
  module Commands
7
7
  class Track < Dry::CLI::Command
8
- include Settings
9
-
10
8
  desc 'Start time entry in Toggl with issue title and id'
11
9
 
12
10
  argument :id, required: true, desc: 'The card short ID'
13
11
 
14
12
  def call(id:)
15
13
  @id = id
16
- 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))
17
15
  end
18
16
 
19
17
  private
@@ -23,7 +21,7 @@ module Dude
23
21
  def task_title
24
22
  client = ProjectManagement::Client.new
25
23
  issue_title = client.get_task_name_by_id(id)
26
- 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)
27
25
  end
28
26
  end
29
27
  end
@@ -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
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative './git/checkout'
4
4
  require_relative './git/current_branch_name'
5
+ require_relative './git/remote_name'
5
6
 
6
7
  module Git
7
8
  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,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative './jira/client'
4
+ require_relative './trello/client'
4
5
 
5
6
  module Dude
6
7
  module ProjectManagement
7
8
  class Client
8
- include Settings
9
-
10
9
  attr_reader :client
11
10
 
12
11
  def initialize
13
- return unless LIST_OF_AVAILABLE_PROJECT_MANAGEMENT_TOOLS.include? settings['PROJECT_MANAGEMENT_TOOL']
12
+ tool = Dude::SETTINGS[:project_management_tool]
13
+ return unless LIST_OF_AVAILABLE_PROJECT_MANAGEMENT_TOOLS.include? tool
14
14
 
15
- @client = Dude::ProjectManagement::Jira::Client.new
15
+ @client = setup_client(tool)
16
16
  end
17
17
 
18
18
  def respond_to_missing?(method_name, include_private = false)
@@ -22,6 +22,10 @@ module Dude
22
22
  def method_missing(method, *args, &block)
23
23
  client.send(method, *args, &block)
24
24
  end
25
+
26
+ def setup_client(tool)
27
+ Object.const_get("Dude::ProjectManagement::#{tool.capitalize}::Client").new
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -4,14 +4,15 @@ module Dude
4
4
  module ProjectManagement
5
5
  module Entities
6
6
  class Issue
7
- attr_accessor :id, :title, :description, :status, :assignee
7
+ attr_accessor :id, :title, :description, :status, :assignee, :url
8
8
 
9
- def initialize(id:, title:, description:, status:, assignee: nil)
10
- @id = id
11
- @title = title
12
- @description = description
13
- @status = status
14
- @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]
15
16
  end
16
17
 
17
18
  def todo?
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'jira-ruby'
4
4
  require_relative './fetch_current_tasks'
5
+ require_relative './fetch_current_task'
5
6
  require_relative './move_task_to_list'
6
7
  require_relative './get_task_name_by_id'
7
8
 
@@ -9,21 +10,23 @@ module Dude
9
10
  module ProjectManagement
10
11
  module Jira
11
12
  class Client
12
- include Settings
13
-
14
13
  attr_reader :client, :project
15
14
 
16
- def initialize
17
- options = {
18
- username: settings['ATLASSIAN_EMAIL'],
19
- password: settings['ATLASSIAN_TOKEN'],
20
- site: settings['ATLASSIAN_URL'],
15
+ def options
16
+ {
17
+ username: Dude::SETTINGS.dig(:jira, :email),
18
+ password: Dude::SETTINGS.dig(:jira, :token),
19
+ site: Dude::SETTINGS.dig(:jira, :project, :url),
21
20
  context_path: '',
22
21
  auth_type: :basic
23
22
  }
23
+ end
24
24
 
25
+ def initialize
25
26
  @client = JIRA::Client.new(options)
26
- @project = client.Project.find(settings['ATLASSIAN_PROJECT_KEY'])
27
+ @project = client.Project.find(Dude::SETTINGS.dig(:jira, :project, :key))
28
+ rescue StandardError
29
+ nil
27
30
  end
28
31
 
29
32
  def respond_to_missing?(method_name, include_private = false)
@@ -38,6 +41,10 @@ module Dude
38
41
  FetchCurrentTasks.new(client).call
39
42
  end
40
43
 
44
+ def fetch_current_task(id)
45
+ FetchCurrentTask.new(client, id: id).call
46
+ end
47
+
41
48
  def move_task_to_list(id, list)
42
49
  MoveTaskToList.new(client, id: id, list_name: list).call
43
50
  end
@@ -45,6 +52,12 @@ module Dude
45
52
  def get_task_name_by_id(id)
46
53
  GetTaskNameById.new(client, id: id).call
47
54
  end
55
+
56
+ def health_check
57
+ @project && true
58
+ rescue StandardError
59
+ false
60
+ end
48
61
  end
49
62
  end
50
63
  end