geet 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -3
  3. data/README.md +25 -24
  4. data/bin/geet +21 -3
  5. data/geet.gemspec +2 -2
  6. data/lib/geet/commandline/configuration.rb +5 -5
  7. data/lib/geet/git/repository.rb +34 -15
  8. data/lib/geet/services/abstract_create_issue.rb +33 -0
  9. data/lib/geet/services/create_gist.rb +6 -4
  10. data/lib/geet/services/create_issue.rb +33 -87
  11. data/lib/geet/services/create_label.rb +7 -6
  12. data/lib/geet/services/create_pr.rb +42 -86
  13. data/lib/geet/services/list_issues.rb +13 -14
  14. data/lib/geet/services/list_labels.rb +4 -3
  15. data/lib/geet/services/list_milestones.rb +12 -11
  16. data/lib/geet/services/list_prs.rb +4 -3
  17. data/lib/geet/services/merge_pr.rb +12 -11
  18. data/lib/geet/shared/constants.rb +9 -0
  19. data/lib/geet/utils/attributes_selection_manager.rb +87 -0
  20. data/lib/geet/utils/manual_list_selection.rb +41 -27
  21. data/lib/geet/utils/string_matching_selection.rb +32 -0
  22. data/lib/geet/version.rb +1 -1
  23. data/spec/integration/create_gist_spec.rb +4 -4
  24. data/spec/integration/create_issue_spec.rb +6 -6
  25. data/spec/integration/create_label_spec.rb +3 -3
  26. data/spec/integration/create_pr_spec.rb +13 -13
  27. data/spec/integration/list_issues_spec.rb +5 -5
  28. data/spec/integration/list_labels_spec.rb +3 -3
  29. data/spec/integration/list_milestones_spec.rb +2 -2
  30. data/spec/integration/list_prs_spec.rb +2 -2
  31. data/spec/integration/merge_pr_spec.rb +2 -2
  32. data/spec/vcr_cassettes/create_issue_upstream.yml +1 -1
  33. data/spec/vcr_cassettes/create_pr.yml +181 -102
  34. data/spec/vcr_cassettes/create_pr_in_auto_mode_create_upstream.yml +1 -1
  35. data/spec/vcr_cassettes/create_pr_in_auto_mode_with_push.yml +1 -1
  36. data/spec/vcr_cassettes/create_pr_upstream.yml +2 -2
  37. metadata +8 -5
  38. 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, output: $stdout)
11
- label = create_label(name, color, output)
11
+ def execute(name, color: generate_random_color)
12
+ label = create_label(name, color)
12
13
 
13
- output.puts "Created with color ##{label.color}"
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, output)
21
- output.puts 'Creating label...'
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
- require 'tmpdir'
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
- MANUAL_LIST_SELECTION_FLAG = '-'.freeze
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
- # :label_patterns
26
- # :reviewer_patterns
17
+ # :labels
18
+ # :reviewers
27
19
  # :no_open_pr
28
20
  #
29
21
  def execute(
30
- title, description, label_patterns: nil, milestone_pattern: nil, reviewer_patterns: nil,
31
- no_open_pr: nil, automated_mode: false, output: $stdout, **
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
- all_labels, all_milestones, all_collaborators = find_all_attribute_entries(
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
- labels = select_entries('label', all_labels, label_patterns, :multiple, :name) if label_patterns
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
- sync_with_upstream_branch(output) if automated_mode
31
+ pr = create_pr(title, description)
44
32
 
45
- pr = create_pr(title, description, output)
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
- output.puts "PR address: #{pr.link}"
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, output) if title
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 find_all_attribute_entries(label_patterns, milestone_pattern, reviewer_patterns, output)
70
- if label_patterns
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 milestone_pattern
76
- output.puts 'Finding milestone...'
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 reviewer_patterns
81
- output.puts 'Finding collaborators...'
82
- reviewers_thread = Thread.new { @repository.collaborators }
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
- labels = labels_thread&.value
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(output)
70
+ def sync_with_upstream_branch
97
71
  if @git_client.upstream_branch
98
- output.puts "Pushing to upstream branch..."
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
- output.puts "Creating upstream branch #{upstream_branch.inspect}..."
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, output)
111
- output.puts 'Creating PR...'
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, output)
117
- assign_user_thread = assign_authenticated_user(pr, output)
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, output) if labels && !labels.empty?
122
- set_milestone_thread = set_milestone(pr, milestone, output) if milestone
123
- request_review_thread = request_review(pr, reviewers, output) if reviewers && !reviewers.empty?
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, output)
132
- output.puts 'Assigning authenticated user...'
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, output)
113
+ def add_labels(pr, selected_labels)
140
114
  labels_list = selected_labels.map(&:name).join(', ')
141
115
 
142
- output.puts "Adding labels #{labels_list}..."
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, output)
150
- output.puts "Setting milestone #{milestone.title}..."
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, output)
158
- output.puts "Requesting review from #{reviewers.join(', ')}..."
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(assignee_pattern: nil, output: $stdout, **)
11
- assignee_thread = find_assignee(assignee_pattern, output) if assignee_pattern
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: assignee)
16
+ issues = @repository.issues(assignee: selected_assignee)
16
17
 
17
18
  issues.each do |issue|
18
- output.puts "#{issue.number}. #{issue.title} (#{issue.link})"
19
+ @out.puts "#{issue.number}. #{issue.title} (#{issue.link})"
19
20
  end
20
21
  end
21
22
 
22
23
  private
23
24
 
24
- def find_assignee(assignee_pattern, output)
25
- output.puts 'Finding assignee...'
25
+ def find_and_select_attributes(assignee)
26
+ selection_manager = Geet::Utils::AttributesSelectionManager.new(@repository, out: @out)
26
27
 
27
- Thread.new do
28
- collaborators = @repository.collaborators
29
- collaborator = collaborators.find { |collaborator| collaborator =~ /#{assignee_pattern}/i }
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(output: $stdout)
11
+ def execute
11
12
  labels = @repository.labels
12
13
 
13
14
  labels.each do |label|
14
- output.puts "- #{label.name} (##{label.color})"
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(output: $stdout)
11
- milestones = find_milestones(output)
12
- issues_by_milestone_number = find_milestone_issues(milestones, output)
11
+ def execute
12
+ milestones = find_milestones
13
+ issues_by_milestone_number = find_milestone_issues(milestones)
13
14
 
14
- output.puts
15
+ @out.puts
15
16
 
16
17
  milestones.each do |milestone|
17
- output.puts milestone_description(milestone)
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
- output.puts " #{issue.number}. #{issue.title} (#{issue.link})"
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(output)
38
- output.puts 'Finding milestones...'
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, output)
44
- output.puts 'Finding issues...'
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(output: $stdout)
11
+ def execute
11
12
  prs = @repository.prs
12
13
 
13
14
  prs.each do |pr|
14
- output.puts "#{pr.number}. #{pr.title} (#{pr.link})"
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, output: $stdout)
14
+ def execute(delete_branch: false)
14
15
  merge_head = find_merge_head
15
- pr = checked_find_branch_pr(merge_head, output)
16
- merge_pr(pr, output)
17
- do_delete_branch(output) if 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, output)
29
- output.puts "Finding PR with head (#{head})..."
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, output)
39
- output.puts "Merging PR ##{pr.number}..."
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(output)
45
- output.puts "Deleting branch #{@git_client.current_branch}..."
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
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geet
4
+ module Shared
5
+ module Constants
6
+ MANUAL_LIST_SELECTION_FLAG = '-'.freeze
7
+ end
8
+ end
9
+ end