geet 0.3.1 → 0.3.2
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.
- 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
|