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
data/lib/dude.rb CHANGED
@@ -1,12 +1,23 @@
1
- require "colorize"
1
+ # frozen_string_literal: true
2
2
 
3
- require "dude/settings"
4
- require "dude/version"
5
- require "dude/commands"
6
- require "dude/git"
3
+ require 'colorize'
4
+
5
+ begin
6
+ require 'pry'
7
+ rescue LoadError
8
+ nil
9
+ end
10
+
11
+ require_relative './dude/settings'
12
+ require_relative './dude/version'
13
+ require_relative './dude/commands'
14
+ require_relative './dude/git'
15
+ require_relative './dude/code_management'
16
+ require_relative './dude/config'
7
17
 
8
18
  module Dude
9
- class ToBeImplementedError < StandardError; end
19
+ SETTINGS = Dude::Config.configure_with('.duderc.yml')
20
+ LIST_OF_AVAILABLE_PROJECT_MANAGEMENT_TOOLS = %w[jira trello].freeze
10
21
 
11
- LIST_OF_AVAILABLE_PROJECT_MANAGEMENT_TOOLS = %w[jira]
22
+ class ToBeImplementedError < StandardError; end
12
23
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './code_management/github/client'
4
+
5
+ module Dude
6
+ module CodeManagement
7
+ module Github
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './create_pull_request'
4
+
5
+ module Dude
6
+ module CodeManagement
7
+ module Github
8
+ class Client
9
+ def client
10
+ @client ||= Faraday.new('https://api.github.com/', {
11
+ headers: { Authorization: "token #{Dude::SETTINGS.dig(:github, :token)}" }
12
+ })
13
+ end
14
+
15
+ def create_pull_request(issue:, owner:, repo:, params:)
16
+ CreatePullRequest.new.call(client, issue: issue, owner: owner, repo: repo, params: params)
17
+ end
18
+
19
+ def health_check
20
+ client.get('https://api.github.com/user').status == 200
21
+ rescue StandardError
22
+ false
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Dude
6
+ module CodeManagement
7
+ module Github
8
+ class CreatePullRequest
9
+ def call(client, issue:, owner:, repo:, params:)
10
+ @issue = issue
11
+ @owner = owner
12
+ @repo = repo
13
+ @params = params
14
+
15
+ response = client.post("https://api.github.com/repos/#{owner}/#{repo}/pulls", body.to_json)
16
+ res = JSON.parse(response.body)
17
+ url = res['html_url']
18
+ puts "Pull request has been created: #{url}"
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :issue, :owner, :repo, :params
24
+
25
+ def body
26
+ {
27
+ title: params[:title] || template['title'],
28
+ body: params[:body] || template['body'],
29
+ head: params[:head],
30
+ base: params[:base]
31
+ }
32
+ end
33
+
34
+ def template
35
+ file = YAML.load_file(File.join(File.dirname(__FILE__), '../../templates/pull_request_template'))
36
+ file.tap do |template|
37
+ template['title'] = fill_variables(template['title'])
38
+ template['body'] = fill_variables(template['body'])
39
+ end
40
+ end
41
+
42
+ def fill_variables(text)
43
+ text
44
+ .then { _1.gsub('{issue_id}', issue.id) }.chomp
45
+ .then { _1.gsub('{issue_url}', issue.url) }
46
+ .then { _1.gsub('{issue_title}', issue.title) }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
data/lib/dude/commands.rb CHANGED
@@ -1,24 +1,33 @@
1
- require "dry/cli"
2
- require_relative "./commands/version"
3
- require_relative "./commands/tasks"
4
- require_relative "./commands/move"
5
- require_relative "./commands/checkout"
6
- require_relative "./commands/start"
7
- require_relative "./commands/track"
8
- require_relative "./commands/stop"
9
- require_relative "./commands/install"
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry/cli'
4
+ require_relative './commands/version'
5
+ require_relative './commands/tasks'
6
+ require_relative './commands/move'
7
+ require_relative './commands/checkout'
8
+ require_relative './commands/start'
9
+ require_relative './commands/track'
10
+ require_relative './commands/stop'
11
+ require_relative './commands/install'
12
+ require_relative './commands/pr'
13
+ require_relative './commands/health_check'
10
14
 
11
15
  module Dude
12
16
  module Commands
13
17
  extend Dry::CLI::Registry
14
18
 
15
- register "install", Dude::Commands::Install, aliases: ["install"]
16
- register "version", Dude::Commands::Version, aliases: ["v", "-v", "--version"]
17
- register "tasks", Dude::Commands::Tasks, aliases: ["t", "-t", "--tasks"]
18
- register "move", Dude::Commands::Move, aliases: ["m", "-m", "--move"]
19
- register "checkout", Dude::Commands::Checkout, aliases: ["co"]
20
- register "track", Dude::Commands::Track, aliases: ["tr"]
21
- register "stop", Dude::Commands::Stop
22
- register "start", Dude::Commands::Start, aliases: ["st"]
19
+ register 'install', Dude::Commands::Install, aliases: ['install']
20
+ register 'version', Dude::Commands::Version, aliases: ['v', '-v', '--version']
21
+ register 'tasks', Dude::Commands::Tasks, aliases: ['t', '-t', '--tasks']
22
+ register 'move', Dude::Commands::Move, aliases: ['m', '-m', '--move']
23
+ register 'checkout', Dude::Commands::Checkout, aliases: ['co']
24
+ register 'track', Dude::Commands::Track, aliases: ['tr']
25
+ register 'stop', Dude::Commands::Stop
26
+ register 'start', Dude::Commands::Start, aliases: ['st']
27
+ register 'healthcheck', Dude::Commands::HealthCheck
28
+
29
+ register 'pr' do |prefix|
30
+ prefix.register 'create', Dude::Commands::PR::Create
31
+ end
23
32
  end
24
33
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module Commands
3
5
  class Checkout < Dry::CLI::Command
4
- desc "Checkout to branch named as current issue"
6
+ desc 'Checkout to branch named as current issue'
5
7
 
6
- argument :id, required: true, desc: "The card short ID"
8
+ argument :id, required: true, desc: 'The card short ID'
7
9
 
8
10
  def call(id:)
9
11
  client = ProjectManagement::Client.new
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../health_check'
4
+
5
+ module Dude
6
+ module Commands
7
+ class HealthCheck < Dry::CLI::Command
8
+ desc 'Run healthcheck for enabled integrations'
9
+
10
+ def call
11
+ Dude::HealthCheck.new.call
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,56 +1,80 @@
1
- require 'dude/settings'
1
+ # frozen_string_literal: true
2
+
3
+ require 'tty-prompt'
4
+ require 'fileutils'
5
+
6
+ require_relative '../settings'
7
+ require_relative '../setup/jira'
8
+ require_relative '../setup/trello'
9
+ require_relative '../setup/toggl'
10
+ require_relative '../setup/github'
2
11
 
3
12
  module Dude
4
13
  module Commands
5
14
  class Install < Dry::CLI::Command
6
- desc "Creates .duderc for future configuration"
15
+ desc 'Creates .duderc for future configuration'
7
16
 
8
17
  def call
9
- path = File.join(Dir.home, Settings::CONFIG_FILE)
10
- if File.exist?(path)
11
- puts "Config file already exists"
12
- else
13
- File.open(path, 'w') {|f| f.write(duderc_file_content) }
14
- puts ".duderc created in your HOME directory"
15
- 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
16
28
  end
17
29
 
18
30
  private
19
31
 
20
- def duderc_file_content
21
- <<~HEREDOC
22
- # Please, don't use quotes and spaces.
23
- # Write all variables using following format: NAME=VALUE
24
- #
25
- # Now jira only (Github, Gitlab, Trello later)
26
- PROJECT_MANAGEMENT_TOOL=jira
27
- ATLASSIAN_EMAIL=
28
- # How to create Atlassian token: https://support.siteimprove.com/hc/en-gb/articles/360004317332-How-to-create-an-API-token-from-your-Atlassian-account
29
- ATLASSIAN_TOKEN=
30
- # URL of your project. Example: https://example.atlassian.net
31
- ATLASSIAN_URL=
32
- # KEY of your project. If your issues have id BT-123 - BT is the key
33
- ATLASSIAN_PROJECT_KEY=
34
- # Just open your atlassian main board and copy id from the url after rapidView=*ID* part.
35
- # Example: https://dealmakerns.atlassian.net/secure/RapidBoard.jspa?rapidView=23&projectKey=DT - 23 is the id
36
- ATLASSIAN_BOARD_ID=
37
-
38
- # Replace it with your project list names. Skip for empty lists
39
- TODO_LIST_NAME=To Do
40
- IN_PROGRESS_LIST_NAME=In Progress
41
- CODE_REVIEW_LIST_NAME=Code Review
42
- TESTING_LIST_NAME=TESTABLE
43
- DONE_LIST_NAME=Done
44
-
45
- # Your Toggl project name
46
- TOGGL_PROJECT_NAME=
47
- # Your Toggl API token can be found at the bottom of the page: https://track.toggl.com/profile
48
- TOGGL_TOKEN=
49
- # Can be copied from url here: https://toggl.com/app/projects/. Example: 123456
50
- TOGGL_WORKSPACE_ID=
51
- # Use the *id* and *title* and specify format for the task titles in Trello or keep it as it is
52
- TOGGL_TASK_FORMAT=[id] title
53
- 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
54
78
  end
55
79
  end
56
80
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module Commands
3
5
  class Move < Dry::CLI::Command
4
- desc "Move task between board columns"
6
+ desc 'Move task between board columns'
5
7
 
6
- argument :id, required: true, desc: "The card short ID"
7
- option :list, desc: "List name for moving card"
8
+ argument :id, required: true, desc: 'The card short ID'
9
+ option :list, desc: 'List name for moving card'
8
10
 
9
11
  def call(id:, **options)
10
12
  client = ProjectManagement::Client.new
@@ -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 '123'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,29 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Dude
2
4
  module Commands
3
5
  class Start < Dry::CLI::Command
4
- include Settings
5
-
6
- desc "Start task (Do checkout, track and move actions)"
6
+ desc 'Start task (Do checkout, track and move actions)'
7
7
 
8
- argument :id, required: true, desc: "The card short ID"
8
+ argument :id, required: true, desc: 'The card short ID'
9
9
 
10
10
  def call(id:)
11
11
  Commands::Move.new.call(id: id, list: selected_list('in_progress'))
12
12
  Commands::Checkout.new.call(id: id)
13
- Commands::Track.new.call(id: id)
13
+ Commands::Track.new.call(id: id) if time_tracking_enabled?
14
14
  end
15
15
 
16
16
  private
17
17
 
18
18
  def selected_list(list)
19
19
  case list
20
- when 'todo' then settings['TODO_LIST_NAME']
21
- when 'in_progress' then settings['IN_PROGRESS_LIST_NAME']
22
- when 'code_review' then settings['CODE_REVIEW_LIST_NAME']
23
- when 'testing' then settings['TESTING_LIST_NAME']
24
- 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]
25
25
  end
26
26
  end
27
+
28
+ def time_tracking_enabled?
29
+ !Dude::SETTINGS.dig(:toggl, :token).nil?
30
+ end
27
31
  end
28
32
  end
29
33
  end