dude-cli 2.0.3 → 2.1.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/verify.yml +32 -0
- data/.rspec +0 -1
- data/.rubocop.yml +13 -0
- data/CHANGELOG.md +7 -3
- data/Gemfile +3 -1
- data/Gemfile.lock +48 -9
- data/LICENCE +20 -0
- data/README.md +32 -6
- data/Rakefile +5 -3
- data/bin/console +4 -3
- data/bin/dude +2 -2
- data/dude.gemspec +25 -18
- data/lib/dude.rb +9 -10
- data/lib/dude/code_management.rb +10 -0
- data/lib/dude/code_management/github/client.rb +23 -0
- data/lib/dude/code_management/github/create_pull_request.rb +53 -0
- data/lib/dude/commands.rb +24 -17
- data/lib/dude/commands/checkout.rb +4 -2
- data/lib/dude/commands/install.rb +32 -18
- data/lib/dude/commands/move.rb +5 -3
- data/lib/dude/commands/pr.rb +11 -0
- data/lib/dude/commands/pr/create.rb +49 -0
- data/lib/dude/commands/pr/remove.rb +15 -0
- data/lib/dude/commands/start.rb +9 -3
- data/lib/dude/commands/stop.rb +4 -2
- data/lib/dude/commands/tasks.rb +6 -3
- data/lib/dude/commands/track.rb +5 -3
- data/lib/dude/commands/version.rb +3 -1
- data/lib/dude/git.rb +3 -0
- data/lib/dude/git/checkout.rb +20 -1
- data/lib/dude/git/current_branch_name.rb +3 -1
- data/lib/dude/git/remote_name.rb +21 -0
- data/lib/dude/project_management/client.rb +14 -6
- data/lib/dude/project_management/entities/issue.rb +10 -7
- data/lib/dude/project_management/jira.rb +2 -1
- data/lib/dude/project_management/jira/client.rb +14 -7
- data/lib/dude/project_management/jira/fetch_current_task.rb +37 -0
- data/lib/dude/project_management/jira/fetch_current_tasks.rb +48 -0
- data/lib/dude/project_management/jira/get_task_name_by_id.rb +1 -1
- data/lib/dude/project_management/jira/move_task_to_list.rb +15 -13
- data/lib/dude/project_management/trello.rb +5 -3
- data/lib/dude/project_management/trello/client.rb +40 -21
- data/lib/dude/project_management/trello/fetch_current_task.rb +43 -0
- data/lib/dude/project_management/trello/fetch_current_tasks.rb +53 -0
- data/lib/dude/project_management/trello/fetch_lists.rb +24 -0
- data/lib/dude/project_management/trello/get_task_name_by_id.rb +25 -0
- data/lib/dude/project_management/trello/move_task_to_list.rb +55 -0
- data/lib/dude/settings.rb +3 -0
- data/lib/dude/templates/pull_request_template +7 -0
- data/lib/dude/time_trackers/toggl.rb +2 -0
- data/lib/dude/time_trackers/toggl/base.rb +4 -0
- data/lib/dude/time_trackers/toggl/start_time_entry.rb +3 -2
- data/lib/dude/time_trackers/toggl/stop_time_entry.rb +3 -1
- data/lib/dude/version.rb +3 -1
- metadata +77 -22
- data/dude-cli-2.0.2.gem +0 -0
- data/lib/dude/project_management/entities/board.rb +0 -9
- data/lib/dude/project_management/jira/get_current_tasks.rb +0 -40
- data/lib/dude/project_management/trello/checkout.rb +0 -4
- data/lib/dude/project_management/trello/get_current_tasks.rb +0 -24
- data/lib/dude/project_management/trello/get_lists.rb +0 -15
- data/lib/dude/project_management/trello/move_tasks_to_list.rb +0 -14
@@ -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
|
@@ -1,5 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './jira/client'
|
4
|
+
require_relative './trello/client'
|
3
5
|
|
4
6
|
module Dude
|
5
7
|
module ProjectManagement
|
@@ -9,16 +11,22 @@ module Dude
|
|
9
11
|
attr_reader :client
|
10
12
|
|
11
13
|
def initialize
|
12
|
-
|
13
|
-
|
14
|
+
tool = settings['PROJECT_MANAGEMENT_TOOL']
|
15
|
+
return unless LIST_OF_AVAILABLE_PROJECT_MANAGEMENT_TOOLS.include? tool
|
16
|
+
|
17
|
+
@client = setup_client(tool)
|
14
18
|
end
|
15
19
|
|
16
20
|
def respond_to_missing?(method_name, include_private = false)
|
17
21
|
client.respond_to_missing?(method_name, include_private)
|
18
22
|
end
|
19
23
|
|
20
|
-
def method_missing(
|
21
|
-
client.send(
|
24
|
+
def method_missing(method, *args, &block)
|
25
|
+
client.send(method, *args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def setup_client(tool)
|
29
|
+
Object.const_get("Dude::ProjectManagement::#{tool.capitalize}::Client").new
|
22
30
|
end
|
23
31
|
end
|
24
32
|
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(
|
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,7 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'jira-ruby'
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
@@ -28,12 +31,16 @@ module Dude
|
|
28
31
|
client.respond_to_missing?(method_name, include_private)
|
29
32
|
end
|
30
33
|
|
31
|
-
def method_missing(
|
32
|
-
client.send(
|
34
|
+
def method_missing(method, *args, &block)
|
35
|
+
client.send(method, *args, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def fetch_current_tasks
|
39
|
+
FetchCurrentTasks.new(client).call
|
33
40
|
end
|
34
41
|
|
35
|
-
def
|
36
|
-
|
42
|
+
def fetch_current_task(id)
|
43
|
+
FetchCurrentTask.new(client, id: id).call
|
37
44
|
end
|
38
45
|
|
39
46
|
def move_task_to_list(id, list)
|
@@ -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
|
+
include Settings
|
10
|
+
|
11
|
+
def initialize(client, id:)
|
12
|
+
@client = client
|
13
|
+
@id = id
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
create_issue(client.Issue.find(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: "#{settings['ATLASSIAN_URL']}/browse/#{issue.key}"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,48 @@
|
|
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
|
+
include Settings
|
10
|
+
|
11
|
+
def initialize(client)
|
12
|
+
@client = client
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
board = client.Board.find(settings['ATLASSIAN_BOARD_ID'])
|
17
|
+
|
18
|
+
all_issues = board_type(board)
|
19
|
+
|
20
|
+
all_issues.map { |issue| create_issue(issue) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :client
|
26
|
+
|
27
|
+
def board_type(board)
|
28
|
+
case board.type
|
29
|
+
when 'kanban' then board.issues
|
30
|
+
when 'simple', 'scrum' then board.sprints(state: 'active').flat_map(&:issues)
|
31
|
+
else raise Dude::ToBeImplementedError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_issue(issue)
|
36
|
+
Entities::Issue.new(
|
37
|
+
id: issue.key,
|
38
|
+
title: issue.summary,
|
39
|
+
description: issue.description,
|
40
|
+
status: issue.status.name,
|
41
|
+
assignee: issue&.assignee&.displayName,
|
42
|
+
url: "#{settings['ATLASSIAN_URL']}/browse/#{issue.key}"
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Dude
|
4
4
|
module ProjectManagement
|
@@ -14,33 +14,35 @@ module Dude
|
|
14
14
|
|
15
15
|
def call
|
16
16
|
issue = client.Issue.find(id)
|
17
|
-
available_transitions = client.Transition.all(:
|
17
|
+
available_transitions = client.Transition.all(issue: issue)
|
18
|
+
transition_id = generate_transition_id(issue, available_transitions)
|
19
|
+
transition = issue.transitions.build
|
20
|
+
transition.save!(transition: { id: transition_id })
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :client, :id, :list_name
|
18
26
|
|
19
|
-
|
27
|
+
def generate_transition_id(issue, available_transitions)
|
28
|
+
if list_name
|
20
29
|
available_transitions.find { |transition| transition.name == list_name }.id
|
21
30
|
else
|
22
31
|
select_list_for_moving(issue, available_transitions).id
|
23
32
|
end
|
24
|
-
|
25
|
-
transition = issue.transitions.build
|
26
|
-
transition.save!(transition: { id: transition_id })
|
27
33
|
end
|
28
34
|
|
29
|
-
|
30
|
-
|
31
|
-
def select_list_for_moving(issuem, available_transitions)
|
32
|
-
puts "Please, select list for moving:".green.bold
|
35
|
+
def select_list_for_moving(_issue, available_transitions)
|
36
|
+
puts 'Please, select list for moving:'.green.bold
|
33
37
|
|
34
38
|
available_transitions.each_with_index do |ea, index|
|
35
39
|
puts "#{index + 1}: #{ea.name.bold}"
|
36
40
|
end
|
37
41
|
|
38
42
|
print "\nList index: ".bold
|
39
|
-
list_index =
|
43
|
+
list_index = $stdin.gets.chomp
|
40
44
|
available_transitions[list_index.to_i - 1]
|
41
45
|
end
|
42
|
-
|
43
|
-
attr_reader :client, :id, :list_name
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
@@ -1,32 +1,51 @@
|
|
1
|
-
#
|
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'
|
2
7
|
|
3
8
|
require 'faraday'
|
4
9
|
require 'json'
|
5
10
|
|
6
11
|
module Dude
|
7
|
-
module
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def faraday_client
|
12
|
-
@faraday_client ||= Faraday.new('https://api.trello.com/', {
|
13
|
-
params: {
|
14
|
-
key: "62b20e9eeab2d6e06145c69178521225",
|
15
|
-
token: "6285fc2d2ff6100a5c341838d0e4acfed3601ae503beb973ddccf1cfab088537"
|
16
|
-
}
|
17
|
-
})
|
18
|
-
end
|
12
|
+
module ProjectManagement
|
13
|
+
module Trello
|
14
|
+
class Client
|
15
|
+
include Settings
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
17
|
+
def client
|
18
|
+
@client ||= Faraday.new('https://api.trello.com/', {
|
19
|
+
params: {
|
20
|
+
key: settings['TRELLO_KEY'],
|
21
|
+
token: settings['TRELLO_TOKEN']
|
22
|
+
}
|
23
|
+
})
|
24
|
+
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
def method_missing(method, *args, &block)
|
27
|
+
faraday_client.send(method, *args, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def respond_to_missing?(method_name, include_private = false)
|
31
|
+
client.respond_to_missing?(method_name, include_private)
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch_current_tasks
|
35
|
+
FetchCurrentTasks.new(client).call
|
36
|
+
end
|
37
|
+
|
38
|
+
def fetch_current_task(id)
|
39
|
+
FetchCurrentTask.new(client, id: id).call
|
40
|
+
end
|
41
|
+
|
42
|
+
def move_task_to_list(id, list)
|
43
|
+
MoveTaskToList.new(client, id: id, list_name: list).call
|
44
|
+
end
|
27
45
|
|
28
|
-
|
29
|
-
|
46
|
+
def get_task_name_by_id(id)
|
47
|
+
GetTaskNameById.new(client, id: id).call
|
48
|
+
end
|
30
49
|
end
|
31
50
|
end
|
32
51
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dude
|
4
|
+
module ProjectManagement
|
5
|
+
module Trello
|
6
|
+
class FetchCurrentTask
|
7
|
+
include Settings
|
8
|
+
|
9
|
+
def initialize(client, id:)
|
10
|
+
@client = client
|
11
|
+
@id = id
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
response = client.get("/1/boards/#{settings['ATLASSIAN_BOARD_ID']}/cards/#{id}")
|
16
|
+
create_issue JSON.parse(response.body)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :client, :id
|
22
|
+
|
23
|
+
def create_issue(issue)
|
24
|
+
Entities::Issue.new(
|
25
|
+
id: issue['idShort'],
|
26
|
+
title: issue['name'],
|
27
|
+
description: issue['desc'],
|
28
|
+
status: settings['IN_PROGRESS_LIST_NAME'], # OMG, let's fix this later
|
29
|
+
assignee: members(issue),
|
30
|
+
url: issue['shortUrl']
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def members(issue)
|
35
|
+
people = issue['idMembers'].map do |person|
|
36
|
+
JSON.parse(client.get("/1/members/#{person}", fields: 'fullName').body)['fullName']
|
37
|
+
end
|
38
|
+
people.empty? ? nil : people.join(', ')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
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 FetchCurrentTasks
|
9
|
+
include Settings
|
10
|
+
|
11
|
+
attr_reader :fetch_lists
|
12
|
+
|
13
|
+
def initialize(client, fetch_lists: nil)
|
14
|
+
@client = client
|
15
|
+
|
16
|
+
@fetch_lists = fetch_lists || FetchLists.new(client)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
lists = fetch_lists.call
|
21
|
+
lists.map { |list| retrieve_list_issues(list) }.flatten
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :client
|
27
|
+
|
28
|
+
def retrieve_list_issues(list)
|
29
|
+
response = client.get("/1/lists/#{list['id']}/cards")
|
30
|
+
body = JSON.parse(response.body)
|
31
|
+
body.map { |issue| create_issue(issue, list) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_issue(issue, current_list)
|
35
|
+
Entities::Issue.new(
|
36
|
+
id: issue['idShort'],
|
37
|
+
title: issue['name'],
|
38
|
+
description: issue['desc'],
|
39
|
+
status: current_list['name'],
|
40
|
+
assignee: members(issue)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
def members(issue)
|
45
|
+
people = issue['idMembers'].map do |person|
|
46
|
+
JSON.parse(client.get("/1/members/#{person}", fields: 'fullName').body)['fullName']
|
47
|
+
end
|
48
|
+
people.empty? ? nil : people.join(', ')
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|