geet 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +25 -24
- data/bin/geet +21 -3
- data/geet.gemspec +2 -2
- data/lib/geet/commandline/configuration.rb +5 -5
- data/lib/geet/git/repository.rb +34 -15
- data/lib/geet/services/abstract_create_issue.rb +33 -0
- data/lib/geet/services/create_gist.rb +6 -4
- data/lib/geet/services/create_issue.rb +33 -87
- data/lib/geet/services/create_label.rb +7 -6
- data/lib/geet/services/create_pr.rb +42 -86
- data/lib/geet/services/list_issues.rb +13 -14
- data/lib/geet/services/list_labels.rb +4 -3
- data/lib/geet/services/list_milestones.rb +12 -11
- data/lib/geet/services/list_prs.rb +4 -3
- data/lib/geet/services/merge_pr.rb +12 -11
- data/lib/geet/shared/constants.rb +9 -0
- data/lib/geet/utils/attributes_selection_manager.rb +87 -0
- data/lib/geet/utils/manual_list_selection.rb +41 -27
- data/lib/geet/utils/string_matching_selection.rb +32 -0
- data/lib/geet/version.rb +1 -1
- data/spec/integration/create_gist_spec.rb +4 -4
- data/spec/integration/create_issue_spec.rb +6 -6
- data/spec/integration/create_label_spec.rb +3 -3
- data/spec/integration/create_pr_spec.rb +13 -13
- data/spec/integration/list_issues_spec.rb +5 -5
- data/spec/integration/list_labels_spec.rb +3 -3
- data/spec/integration/list_milestones_spec.rb +2 -2
- data/spec/integration/list_prs_spec.rb +2 -2
- data/spec/integration/merge_pr_spec.rb +2 -2
- data/spec/vcr_cassettes/create_issue_upstream.yml +1 -1
- data/spec/vcr_cassettes/create_pr.yml +181 -102
- data/spec/vcr_cassettes/create_pr_in_auto_mode_create_upstream.yml +1 -1
- data/spec/vcr_cassettes/create_pr_in_auto_mode_with_push.yml +1 -1
- data/spec/vcr_cassettes/create_pr_upstream.yml +2 -2
- metadata +8 -5
- data/lib/geet/utils/pattern_matching_selection.rb +0 -27
@@ -3,22 +3,23 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class CreateLabel
|
6
|
-
def initialize(repository)
|
6
|
+
def initialize(repository, out: $stdout)
|
7
7
|
@repository = repository
|
8
|
+
@out = out
|
8
9
|
end
|
9
10
|
|
10
|
-
def execute(name, color: generate_random_color
|
11
|
-
label = create_label(name, color
|
11
|
+
def execute(name, color: generate_random_color)
|
12
|
+
label = create_label(name, color)
|
12
13
|
|
13
|
-
|
14
|
+
@out.puts "Created with color ##{label.color}"
|
14
15
|
|
15
16
|
label
|
16
17
|
end
|
17
18
|
|
18
19
|
private
|
19
20
|
|
20
|
-
def create_label(name, color
|
21
|
-
|
21
|
+
def create_label(name, color)
|
22
|
+
@out.puts 'Creating label...'
|
22
23
|
|
23
24
|
@repository.create_label(name, color)
|
24
25
|
end
|
@@ -1,60 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require_relative '../helpers/os_helper.rb'
|
5
|
-
require_relative '../utils/manual_list_selection.rb'
|
6
|
-
require_relative '../utils/pattern_matching_selection.rb'
|
3
|
+
require_relative 'abstract_create_issue'
|
7
4
|
|
8
5
|
module Geet
|
9
6
|
module Services
|
10
|
-
class CreatePr
|
11
|
-
include Geet::Helpers::OsHelper
|
12
|
-
|
7
|
+
class CreatePr < AbstractCreateIssue
|
13
8
|
DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
|
14
9
|
|
15
|
-
|
16
|
-
|
17
|
-
SUMMARY_BACKUP_FILENAME = File.join(Dir.tmpdir, 'last_geet_edited_summary.md')
|
18
|
-
|
19
|
-
def initialize(repository, git_client: DEFAULT_GIT_CLIENT)
|
20
|
-
@repository = repository
|
10
|
+
def initialize(repository, out: $stdout, git_client: DEFAULT_GIT_CLIENT)
|
11
|
+
super(repository)
|
21
12
|
@git_client = git_client
|
13
|
+
@out = out
|
22
14
|
end
|
23
15
|
|
24
16
|
# options:
|
25
|
-
# :
|
26
|
-
# :
|
17
|
+
# :labels
|
18
|
+
# :reviewers
|
27
19
|
# :no_open_pr
|
28
20
|
#
|
29
21
|
def execute(
|
30
|
-
title, description,
|
31
|
-
no_open_pr: nil, automated_mode: false,
|
22
|
+
title, description, labels: nil, milestone: nil, reviewers: nil,
|
23
|
+
no_open_pr: nil, automated_mode: false, **
|
32
24
|
)
|
33
25
|
ensure_clean_tree if automated_mode
|
34
26
|
|
35
|
-
|
36
|
-
label_patterns, milestone_pattern, reviewer_patterns, output
|
37
|
-
)
|
27
|
+
selected_labels, selected_milestone, selected_reviewers = find_and_select_attributes(labels, milestone, reviewers)
|
38
28
|
|
39
|
-
|
40
|
-
milestone, _ = select_entries('milestone', all_milestones, milestone_pattern, :single, :title) if milestone_pattern
|
41
|
-
reviewers = select_entries('reviewer', all_collaborators, reviewer_patterns, :multiple, nil) if reviewer_patterns
|
29
|
+
sync_with_upstream_branch if automated_mode
|
42
30
|
|
43
|
-
|
31
|
+
pr = create_pr(title, description)
|
44
32
|
|
45
|
-
pr
|
46
|
-
|
47
|
-
edit_pr(pr, labels, milestone, reviewers, output)
|
33
|
+
edit_pr(pr, selected_labels, selected_milestone, selected_reviewers)
|
48
34
|
|
49
35
|
if no_open_pr
|
50
|
-
|
36
|
+
@out.puts "PR address: #{pr.link}"
|
51
37
|
else
|
52
38
|
open_file_with_default_application(pr.link)
|
53
39
|
end
|
54
40
|
|
55
41
|
pr
|
56
42
|
rescue => error
|
57
|
-
save_summary(title, description
|
43
|
+
save_summary(title, description) if title
|
58
44
|
raise
|
59
45
|
end
|
60
46
|
|
@@ -66,61 +52,49 @@ module Geet
|
|
66
52
|
raise 'The working tree is not clean!' if !@git_client.working_tree_clean?
|
67
53
|
end
|
68
54
|
|
69
|
-
def
|
70
|
-
|
71
|
-
output.puts 'Finding labels...'
|
72
|
-
labels_thread = Thread.new { @repository.labels }
|
73
|
-
end
|
55
|
+
def find_and_select_attributes(labels, milestone, reviewers)
|
56
|
+
selection_manager = Geet::Utils::AttributesSelectionManager.new(@repository, out: @out)
|
74
57
|
|
75
|
-
if
|
76
|
-
|
77
|
-
milestone_thread = Thread.new { @repository.milestones }
|
78
|
-
end
|
58
|
+
selection_manager.add_attribute(:labels, 'label', labels, :multiple, name_method: :name) if labels
|
59
|
+
selection_manager.add_attribute(:milestones, 'milestone', milestone, :single, name_method: :title) if milestone
|
79
60
|
|
80
|
-
if
|
81
|
-
|
82
|
-
|
61
|
+
if reviewers
|
62
|
+
selection_manager.add_attribute(:collaborators, 'reviewer', reviewers, :multiple) do |all_reviewers|
|
63
|
+
all_reviewers - [@repository.authenticated_user]
|
64
|
+
end
|
83
65
|
end
|
84
66
|
|
85
|
-
|
86
|
-
milestones = milestone_thread&.value
|
87
|
-
reviewers = reviewers_thread&.value
|
88
|
-
|
89
|
-
raise "No labels found!" if label_patterns && labels.empty?
|
90
|
-
raise "No milestones found!" if milestone_pattern && milestones.empty?
|
91
|
-
raise "No collaborators found!" if reviewer_patterns && reviewers.empty?
|
92
|
-
|
93
|
-
[labels, milestones, reviewers]
|
67
|
+
selection_manager.select_attributes
|
94
68
|
end
|
95
69
|
|
96
|
-
def sync_with_upstream_branch
|
70
|
+
def sync_with_upstream_branch
|
97
71
|
if @git_client.upstream_branch
|
98
|
-
|
72
|
+
@out.puts "Pushing to upstream branch..."
|
99
73
|
|
100
74
|
@git_client.push
|
101
75
|
else
|
102
76
|
upstream_branch = @git_client.current_branch
|
103
77
|
|
104
|
-
|
78
|
+
@out.puts "Creating upstream branch #{upstream_branch.inspect}..."
|
105
79
|
|
106
80
|
@git_client.push(upstream_branch: upstream_branch)
|
107
81
|
end
|
108
82
|
end
|
109
83
|
|
110
|
-
def create_pr(title, description
|
111
|
-
|
84
|
+
def create_pr(title, description)
|
85
|
+
@out.puts 'Creating PR...'
|
112
86
|
|
113
87
|
@repository.create_pr(title, description, @git_client.current_branch)
|
114
88
|
end
|
115
89
|
|
116
|
-
def edit_pr(pr, labels, milestone, reviewers
|
117
|
-
assign_user_thread = assign_authenticated_user(pr
|
90
|
+
def edit_pr(pr, labels, milestone, reviewers)
|
91
|
+
assign_user_thread = assign_authenticated_user(pr)
|
118
92
|
|
119
93
|
# labels/reviewers can be nil (parameter not passed) or empty array (parameter passed, but
|
120
94
|
# nothing selected)
|
121
|
-
add_labels_thread = add_labels(pr, labels
|
122
|
-
set_milestone_thread = set_milestone(pr, milestone
|
123
|
-
request_review_thread = request_review(pr, reviewers
|
95
|
+
add_labels_thread = add_labels(pr, labels) if labels && !labels.empty?
|
96
|
+
set_milestone_thread = set_milestone(pr, milestone) if milestone
|
97
|
+
request_review_thread = request_review(pr, reviewers) if reviewers && !reviewers.empty?
|
124
98
|
|
125
99
|
assign_user_thread.join
|
126
100
|
add_labels_thread&.join
|
@@ -128,57 +102,39 @@ module Geet
|
|
128
102
|
request_review_thread&.join
|
129
103
|
end
|
130
104
|
|
131
|
-
def assign_authenticated_user(pr
|
132
|
-
|
105
|
+
def assign_authenticated_user(pr)
|
106
|
+
@out.puts 'Assigning authenticated user...'
|
133
107
|
|
134
108
|
Thread.new do
|
135
109
|
pr.assign_users(@repository.authenticated_user)
|
136
110
|
end
|
137
111
|
end
|
138
112
|
|
139
|
-
def add_labels(pr, selected_labels
|
113
|
+
def add_labels(pr, selected_labels)
|
140
114
|
labels_list = selected_labels.map(&:name).join(', ')
|
141
115
|
|
142
|
-
|
116
|
+
@out.puts "Adding labels #{labels_list}..."
|
143
117
|
|
144
118
|
Thread.new do
|
145
119
|
pr.add_labels(selected_labels.map(&:name))
|
146
120
|
end
|
147
121
|
end
|
148
122
|
|
149
|
-
def set_milestone(pr, milestone
|
150
|
-
|
123
|
+
def set_milestone(pr, milestone)
|
124
|
+
@out.puts "Setting milestone #{milestone.title}..."
|
151
125
|
|
152
126
|
Thread.new do
|
153
127
|
pr.edit(milestone: milestone.number)
|
154
128
|
end
|
155
129
|
end
|
156
130
|
|
157
|
-
def request_review(pr, reviewers
|
158
|
-
|
131
|
+
def request_review(pr, reviewers)
|
132
|
+
@out.puts "Requesting review from #{reviewers.join(', ')}..."
|
159
133
|
|
160
134
|
Thread.new do
|
161
135
|
pr.request_review(reviewers)
|
162
136
|
end
|
163
137
|
end
|
164
|
-
|
165
|
-
def save_summary(title, description, output)
|
166
|
-
summary = "#{title}\n\n#{description}".strip + "\n"
|
167
|
-
|
168
|
-
IO.write(SUMMARY_BACKUP_FILENAME, summary)
|
169
|
-
|
170
|
-
output.puts "Error! Saved summary to #{SUMMARY_BACKUP_FILENAME}"
|
171
|
-
end
|
172
|
-
|
173
|
-
# Generic helpers
|
174
|
-
|
175
|
-
def select_entries(entry_type, entries, raw_patterns, selection_type, instance_method)
|
176
|
-
if raw_patterns == MANUAL_LIST_SELECTION_FLAG
|
177
|
-
Geet::Utils::ManualListSelection.new.select(entry_type, entries, selection_type, instance_method: instance_method)
|
178
|
-
else
|
179
|
-
Geet::Utils::PatternMatchingSelection.new.select(entry_type, entries, raw_patterns, instance_method: instance_method)
|
180
|
-
end
|
181
|
-
end
|
182
138
|
end
|
183
139
|
end
|
184
140
|
end
|
@@ -1,34 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../utils/attributes_selection_manager'
|
4
|
+
|
3
5
|
module Geet
|
4
6
|
module Services
|
5
7
|
class ListIssues
|
6
|
-
def initialize(repository)
|
8
|
+
def initialize(repository, out: $stdout)
|
7
9
|
@repository = repository
|
10
|
+
@out = out
|
8
11
|
end
|
9
12
|
|
10
|
-
def execute(
|
11
|
-
|
12
|
-
|
13
|
-
assignee = assignee_thread&.join&.value
|
13
|
+
def execute(assignee: nil, **)
|
14
|
+
selected_assignee = find_and_select_attributes(assignee) if assignee
|
14
15
|
|
15
|
-
issues = @repository.issues(assignee:
|
16
|
+
issues = @repository.issues(assignee: selected_assignee)
|
16
17
|
|
17
18
|
issues.each do |issue|
|
18
|
-
|
19
|
+
@out.puts "#{issue.number}. #{issue.title} (#{issue.link})"
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
23
|
private
|
23
24
|
|
24
|
-
def
|
25
|
-
|
25
|
+
def find_and_select_attributes(assignee)
|
26
|
+
selection_manager = Geet::Utils::AttributesSelectionManager.new(@repository, out: @out)
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
collaborator || raise("No collaborator found for pattern: #{assignee_pattern.inspect}")
|
31
|
-
end
|
28
|
+
selection_manager.add_attribute(:collaborators, 'assignee', assignee, :single)
|
29
|
+
|
30
|
+
selection_manager.select_attributes
|
32
31
|
end
|
33
32
|
end
|
34
33
|
end
|
@@ -3,15 +3,16 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListLabels
|
6
|
-
def initialize(repository)
|
6
|
+
def initialize(repository, out: $stdout)
|
7
7
|
@repository = repository
|
8
|
+
@out = out
|
8
9
|
end
|
9
10
|
|
10
|
-
def execute
|
11
|
+
def execute
|
11
12
|
labels = @repository.labels
|
12
13
|
|
13
14
|
labels.each do |label|
|
14
|
-
|
15
|
+
@out.puts "- #{label.name} (##{label.color})"
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
@@ -3,23 +3,24 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListMilestones
|
6
|
-
def initialize(repository)
|
6
|
+
def initialize(repository, out: $output)
|
7
7
|
@repository = repository
|
8
|
+
@out = out
|
8
9
|
end
|
9
10
|
|
10
|
-
def execute
|
11
|
-
milestones = find_milestones
|
12
|
-
issues_by_milestone_number = find_milestone_issues(milestones
|
11
|
+
def execute
|
12
|
+
milestones = find_milestones
|
13
|
+
issues_by_milestone_number = find_milestone_issues(milestones)
|
13
14
|
|
14
|
-
|
15
|
+
@out.puts
|
15
16
|
|
16
17
|
milestones.each do |milestone|
|
17
|
-
|
18
|
+
@out.puts milestone_description(milestone)
|
18
19
|
|
19
20
|
milestone_issues = issues_by_milestone_number[milestone.number]
|
20
21
|
|
21
22
|
milestone_issues.each do |issue|
|
22
|
-
|
23
|
+
@out.puts " #{issue.number}. #{issue.title} (#{issue.link})"
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
@@ -34,14 +35,14 @@ module Geet
|
|
34
35
|
description
|
35
36
|
end
|
36
37
|
|
37
|
-
def find_milestones
|
38
|
-
|
38
|
+
def find_milestones
|
39
|
+
@out.puts 'Finding milestones...'
|
39
40
|
|
40
41
|
@repository.milestones
|
41
42
|
end
|
42
43
|
|
43
|
-
def find_milestone_issues(milestones
|
44
|
-
|
44
|
+
def find_milestone_issues(milestones)
|
45
|
+
@out.puts 'Finding issues...'
|
45
46
|
|
46
47
|
# Interestingly, on MRI, concurrent hash access is not a problem without mutex,
|
47
48
|
# since due to the GIL, only one thread at a time will actually access it.
|
@@ -3,15 +3,16 @@
|
|
3
3
|
module Geet
|
4
4
|
module Services
|
5
5
|
class ListPrs
|
6
|
-
def initialize(repository)
|
6
|
+
def initialize(repository, out: $stdout)
|
7
7
|
@repository = repository
|
8
|
+
@out = out
|
8
9
|
end
|
9
10
|
|
10
|
-
def execute
|
11
|
+
def execute
|
11
12
|
prs = @repository.prs
|
12
13
|
|
13
14
|
prs.each do |pr|
|
14
|
-
|
15
|
+
@out.puts "#{pr.number}. #{pr.title} (#{pr.link})"
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
@@ -5,16 +5,17 @@ module Geet
|
|
5
5
|
class MergePr
|
6
6
|
DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
|
7
7
|
|
8
|
-
def initialize(repository, git_client: DEFAULT_GIT_CLIENT)
|
8
|
+
def initialize(repository, out: $stdout, git_client: DEFAULT_GIT_CLIENT)
|
9
9
|
@repository = repository
|
10
|
+
@out = out
|
10
11
|
@git_client = git_client
|
11
12
|
end
|
12
13
|
|
13
|
-
def execute(delete_branch: false
|
14
|
+
def execute(delete_branch: false)
|
14
15
|
merge_head = find_merge_head
|
15
|
-
pr = checked_find_branch_pr(merge_head
|
16
|
-
merge_pr(pr
|
17
|
-
do_delete_branch
|
16
|
+
pr = checked_find_branch_pr(merge_head)
|
17
|
+
merge_pr(pr)
|
18
|
+
do_delete_branch if delete_branch
|
18
19
|
pr
|
19
20
|
end
|
20
21
|
|
@@ -25,8 +26,8 @@ module Geet
|
|
25
26
|
end
|
26
27
|
|
27
28
|
# Expect to find only one.
|
28
|
-
def checked_find_branch_pr(head
|
29
|
-
|
29
|
+
def checked_find_branch_pr(head)
|
30
|
+
@out.puts "Finding PR with head (#{head})..."
|
30
31
|
|
31
32
|
prs = @repository.prs(head: head)
|
32
33
|
|
@@ -35,14 +36,14 @@ module Geet
|
|
35
36
|
prs[0]
|
36
37
|
end
|
37
38
|
|
38
|
-
def merge_pr(pr
|
39
|
-
|
39
|
+
def merge_pr(pr)
|
40
|
+
@out.puts "Merging PR ##{pr.number}..."
|
40
41
|
|
41
42
|
pr.merge
|
42
43
|
end
|
43
44
|
|
44
|
-
def do_delete_branch
|
45
|
-
|
45
|
+
def do_delete_branch
|
46
|
+
@out.puts "Deleting branch #{@git_client.current_branch}..."
|
46
47
|
|
47
48
|
@repository.delete_branch(@git_client.current_branch)
|
48
49
|
end
|