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.
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