geet 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -10
  3. data/Gemfile.lock +8 -2
  4. data/README.md +27 -2
  5. data/Rakefile +3 -1
  6. data/bin/geet +37 -17
  7. data/geet.gemspec +3 -1
  8. data/lib/geet/commandline/configuration.rb +18 -5
  9. data/lib/geet/commandline/editor.rb +14 -24
  10. data/lib/geet/git/repository.rb +30 -84
  11. data/lib/geet/github/api_interface.rb +11 -3
  12. data/lib/geet/github/gist.rb +1 -0
  13. data/lib/geet/gitlab/api_interface.rb +5 -2
  14. data/lib/geet/helpers/os_helper.rb +36 -3
  15. data/lib/geet/helpers/summary_helper.rb +20 -0
  16. data/lib/geet/resources/{edit_summary_template.md → templates/edit_summary.md} +0 -3
  17. data/lib/geet/services/create_gist.rb +18 -2
  18. data/lib/geet/services/create_issue.rb +46 -21
  19. data/lib/geet/services/create_label.rb +8 -4
  20. data/lib/geet/services/create_pr.rb +67 -18
  21. data/lib/geet/services/list_issues.rb +9 -5
  22. data/lib/geet/services/list_labels.rb +6 -2
  23. data/lib/geet/services/list_milestones.rb +11 -7
  24. data/lib/geet/services/list_prs.rb +6 -2
  25. data/lib/geet/services/merge_pr.rb +18 -11
  26. data/lib/geet/utils/git_client.rb +160 -0
  27. data/lib/geet/utils/manual_list_selection.rb +41 -23
  28. data/lib/geet/version.rb +1 -1
  29. data/spec/integration/create_gist_spec.rb +2 -5
  30. data/spec/integration/create_issue_spec.rb +10 -10
  31. data/spec/integration/create_label_spec.rb +30 -5
  32. data/spec/integration/create_pr_spec.rb +85 -10
  33. data/spec/integration/list_issues_spec.rb +12 -11
  34. data/spec/integration/list_labels_spec.rb +28 -5
  35. data/spec/integration/list_milestones_spec.rb +30 -3
  36. data/spec/integration/list_prs_spec.rb +8 -7
  37. data/spec/integration/merge_pr_spec.rb +8 -7
  38. data/spec/vcr_cassettes/create_gist_private.yml +1 -1
  39. data/spec/vcr_cassettes/create_gist_public.yml +1 -1
  40. data/spec/vcr_cassettes/create_issue.yml +9 -9
  41. data/spec/vcr_cassettes/create_issue_upstream.yml +3 -3
  42. data/spec/vcr_cassettes/create_label.yml +1 -1
  43. data/spec/vcr_cassettes/create_label_upstream.yml +80 -0
  44. data/spec/vcr_cassettes/create_label_with_random_color.yml +1 -1
  45. data/spec/vcr_cassettes/create_pr.yml +13 -13
  46. data/spec/vcr_cassettes/create_pr_in_auto_mode_create_upstream.yml +235 -0
  47. data/spec/vcr_cassettes/create_pr_in_auto_mode_with_push.yml +235 -0
  48. data/spec/vcr_cassettes/create_pr_upstream.yml +4 -4
  49. data/spec/vcr_cassettes/github_com/list_issues.yml +5 -5
  50. data/spec/vcr_cassettes/github_com/list_issues_upstream.yml +6 -6
  51. data/spec/vcr_cassettes/github_com/list_issues_with_assignee.yml +4 -4
  52. data/spec/vcr_cassettes/github_com/list_labels.yml +1 -1
  53. data/spec/vcr_cassettes/github_com/list_labels_upstream.yml +78 -0
  54. data/spec/vcr_cassettes/gitlab_com/list_issues.yml +5 -5
  55. data/spec/vcr_cassettes/gitlab_com/list_labels.yml +1 -1
  56. data/spec/vcr_cassettes/list_milestones.yml +15 -15
  57. data/spec/vcr_cassettes/list_milestones_upstream.yml +155 -0
  58. data/spec/vcr_cassettes/list_prs.yml +6 -6
  59. data/spec/vcr_cassettes/list_prs_upstream.yml +3 -3
  60. data/spec/vcr_cassettes/merge_pr.yml +2 -2
  61. data/spec/vcr_cassettes/merge_pr_with_branch_deletion.yml +2 -2
  62. metadata +24 -4
  63. data/lib/geet/utils/git.rb +0 -30
@@ -11,9 +11,12 @@ module Geet
11
11
  API_AUTH_USER = '' # We don't need the login, as the API key uniquely identifies the user
12
12
  API_BASE_URL = 'https://api.github.com'
13
13
 
14
- def initialize(api_token, repository_path, upstream)
14
+ # repo_path: optional for operations that don't require a repository, eg. gist creation.
15
+ # upstream: boolean; makes sense only when :repo_path is set.
16
+ #
17
+ def initialize(api_token, repo_path: nil, upstream: nil)
15
18
  @api_token = api_token
16
- @repository_path = repository_path
19
+ @repository_path = repo_path
17
20
  @upstream = upstream
18
21
  end
19
22
 
@@ -69,7 +72,12 @@ module Geet
69
72
 
70
73
  def api_url(api_path)
71
74
  url = API_BASE_URL
72
- url += "/repos/#{@repository_path}/" if !api_path.start_with?('/')
75
+
76
+ if !api_path.start_with?('/')
77
+ raise 'Missing repo path!' if @repository_path.nil?
78
+ url += "/repos/#{@repository_path}/"
79
+ end
80
+
73
81
  url + api_path
74
82
  end
75
83
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'abstract_issue'
4
+ require_relative '../github/gist'
4
5
 
5
6
  module Geet
6
7
  module Github
@@ -11,9 +11,12 @@ module Geet
11
11
  class ApiInterface
12
12
  API_BASE_URL = 'https://gitlab.com/api/v4'
13
13
 
14
- def initialize(api_token, path_with_namespace, upstream)
14
+ # repo_path: "path/namespace"; required for the current GitLab operations.
15
+ # upstream: boolean; required for the current GitLab operations.
16
+ #
17
+ def initialize(api_token, repo_path:, upstream:)
15
18
  @api_token = api_token
16
- @path_with_namespace = path_with_namespace
19
+ @path_with_namespace = repo_path
17
20
  @upstream = upstream
18
21
  end
19
22
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'English'
4
+ require 'open3'
4
5
  require 'shellwords'
5
6
 
6
7
  module Geet
@@ -14,10 +15,42 @@ module Geet
14
15
  end
15
16
  end
16
17
 
17
- def execute_command(description, *command_tokens)
18
- system(*command_tokens.map(&:shellescape))
18
+ # Executes the command.
19
+ #
20
+ # If the command doesn't execute successfully, it will raise an error.
21
+ #
22
+ # On non-interactive runs, the stdout content is returned, stripped of the surrounding
23
+ # whitespaces.
24
+ #
25
+ # description: optional string, to make the error clearer.
26
+ # interactive: set when required; in this case, a different API will be used (`system()`
27
+ # instead of `popen3`).
28
+ # silent_stderr: don't print the stderr output
29
+ #
30
+ def execute_command(command, description: nil, interactive: false, silent_stderr: false)
31
+ description_message = " on #{description}" if description
19
32
 
20
- raise "Error during #{description} (exit status: #{$CHILD_STATUS.exitstatus})" if !$CHILD_STATUS.success?
33
+ if interactive
34
+ system(command)
35
+
36
+ if !$CHILD_STATUS.success?
37
+ raise "Error#{description_message} (exit status: #{$CHILD_STATUS.exitstatus})"
38
+ end
39
+ else
40
+ Open3.popen3(command) do |_, stdout, stderr, wait_thread|
41
+ stdout_content = stdout.read
42
+ stderr_content = stderr.read
43
+
44
+ puts stderr_content if stderr_content != '' && !silent_stderr
45
+
46
+ if !wait_thread.value.success?
47
+ error_message = stderr_content.lines.first.strip
48
+ raise "Error#{description_message}: #{error_message})"
49
+ end
50
+
51
+ stdout_content.strip
52
+ end
53
+ end
21
54
  end
22
55
  end
23
56
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Geet
4
+ module Helpers
5
+ module SummaryHelper
6
+ # Split the summary in title and description.
7
+ # The description is optional, but the title mandatory.
8
+ #
9
+ def split_summary(summary)
10
+ raise "Missing title in summary!" if summary.to_s.strip.empty?
11
+
12
+ title, description = summary.split(/\r|\n/, 2)
13
+
14
+ # The title may have a residual newline char; the description may not be present,
15
+ # or have multiple blank lines.
16
+ [title.strip, description.to_s.strip]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,6 +1,3 @@
1
-
2
-
3
- ------------------------ >8 ------------------------
4
1
  Please enter above, the title and description for your changes.
5
2
  The first line is the title, and it's mandatory; lines between
6
3
  the second and the separator above, if present, are the description;
@@ -1,25 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../helpers/os_helper.rb'
4
+ require_relative '../github/api_interface.rb'
5
+ require_relative '../github/gist.rb'
4
6
 
5
7
  module Geet
6
8
  module Services
7
9
  class CreateGist
8
10
  include Geet::Helpers::OsHelper
9
11
 
12
+ API_TOKEN_KEY = 'GITHUB_API_TOKEN'
13
+ DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
14
+
15
+ def initialize
16
+ api_token = extract_env_api_token
17
+ @api_interface = Geet::Github::ApiInterface.new(api_token)
18
+ end
19
+
10
20
  # options:
11
21
  # :description
12
22
  # :publik: defaults to false
13
23
  # :no_browse defaults to false
14
24
  #
15
- def execute(repository, full_filename, description: nil, publik: false, no_browse: false, output: $stdout)
25
+ def execute(full_filename, description: nil, publik: false, no_browse: false, output: $stdout)
16
26
  content = IO.read(full_filename)
17
27
 
18
28
  gist_access = publik ? 'public' : 'private'
19
29
  output.puts "Creating a #{gist_access} gist..."
20
30
 
21
31
  filename = File.basename(full_filename)
22
- gist = repository.create_gist(filename, content, description: description, publik: publik)
32
+ gist = Geet::Github::Gist.create(filename, content, @api_interface, description: description, publik: publik)
23
33
 
24
34
  if no_browse
25
35
  output.puts "Gist address: #{gist.link}"
@@ -27,6 +37,12 @@ module Geet
27
37
  open_file_with_default_application(gist.link)
28
38
  end
29
39
  end
40
+
41
+ private
42
+
43
+ def extract_env_api_token
44
+ ENV[API_TOKEN_KEY] || raise("#{API_TOKEN_KEY} not set!")
45
+ end
30
46
  end
31
47
  end
32
48
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tmpdir'
3
4
  require_relative '../helpers/os_helper.rb'
4
5
  require_relative '../utils/manual_list_selection.rb'
5
6
  require_relative '../utils/pattern_matching_selection.rb'
@@ -11,6 +12,12 @@ module Geet
11
12
 
12
13
  MANUAL_LIST_SELECTION_FLAG = '-'.freeze
13
14
 
15
+ SUMMARY_BACKUP_FILENAME = File.join(Dir.tmpdir, 'last_geet_edited_summary.md')
16
+
17
+ def initialize(repository)
18
+ @repository = repository
19
+ end
20
+
14
21
  # options:
15
22
  # :label_patterns
16
23
  # :milestone_pattern: number or description pattern.
@@ -18,21 +25,21 @@ module Geet
18
25
  # :no_open_issue
19
26
  #
20
27
  def execute(
21
- repository, title, description,
28
+ title, description,
22
29
  label_patterns: nil, milestone_pattern: nil, assignee_patterns: nil, no_open_issue: nil,
23
30
  output: $stdout, **
24
31
  )
25
32
  all_labels, all_milestones, all_collaborators = find_all_attribute_entries(
26
- repository, label_patterns, milestone_pattern, assignee_patterns, output
33
+ label_patterns, milestone_pattern, assignee_patterns, output
27
34
  )
28
35
 
29
36
  labels = select_entries('label', all_labels, label_patterns, :multiple, :name) if label_patterns
30
37
  milestone, _ = select_entries('milestone', all_milestones, milestone_pattern, :single, :title) if milestone_pattern
31
- assignees = select_entries('collaborator', all_collaborators, assignee_patterns, :multiple, nil) if assignee_patterns
38
+ assignees = select_entries('assignee', all_collaborators, assignee_patterns, :multiple, nil) if assignee_patterns
32
39
 
33
- issue = create_issue(repository, title, description, output)
40
+ issue = create_issue(title, description, output)
34
41
 
35
- edit_issue(repository, issue, labels, milestone, assignees, output)
42
+ edit_issue(issue, labels, milestone, assignees, output)
36
43
 
37
44
  if no_open_issue
38
45
  output.puts "Issue address: #{issue.link}"
@@ -41,54 +48,64 @@ module Geet
41
48
  end
42
49
 
43
50
  issue
51
+ rescue => error
52
+ save_summary(title, description, output) if title
53
+ raise
44
54
  end
45
55
 
46
56
  private
47
57
 
48
58
  # Internal actions
49
59
 
50
- def find_all_attribute_entries(repository, label_patterns, milestone_pattern, assignee_patterns, output)
60
+ def find_all_attribute_entries(label_patterns, milestone_pattern, assignee_patterns, output)
51
61
  if label_patterns
52
62
  output.puts 'Finding labels...'
53
- labels_thread = Thread.new { repository.labels }
63
+ labels_thread = Thread.new { @repository.labels }
54
64
  end
55
65
 
56
66
  if milestone_pattern
57
67
  output.puts 'Finding milestone...'
58
- milestone_thread = Thread.new { repository.milestones }
68
+ milestone_thread = Thread.new { @repository.milestones }
59
69
  end
60
70
 
61
71
  if assignee_patterns
62
72
  output.puts 'Finding collaborators...'
63
- reviewers_thread = Thread.new { repository.collaborators }
73
+ assignees_thread = Thread.new { @repository.collaborators }
64
74
  end
65
75
 
66
76
  labels = labels_thread&.value
67
77
  milestones = milestone_thread&.value
68
- reviewers = reviewers_thread&.value
78
+ assignees = assignees_thread&.value
69
79
 
70
- [labels, milestones, reviewers]
80
+ raise "No labels found!" if label_patterns && labels.empty?
81
+ raise "No milestones found!" if milestone_pattern && milestones.empty?
82
+ raise "No collaborators found!" if assignee_patterns && assignees.empty?
83
+
84
+ [labels, milestones, assignees]
71
85
  end
72
86
 
73
- def create_issue(repository, title, description, output)
87
+ def create_issue(title, description, output)
74
88
  output.puts 'Creating the issue...'
75
89
 
76
- issue = repository.create_issue(title, description)
90
+ issue = @repository.create_issue(title, description)
77
91
  end
78
92
 
79
- def edit_issue(repository, issue, labels, milestone, assignees, output)
80
- add_labels_thread = add_labels(issue, labels, output) if labels
93
+ def edit_issue(issue, labels, milestone, assignees, output)
94
+ # labels can be nil (parameter not passed) or empty array (parameter passed, but nothing
95
+ # selected)
96
+ add_labels_thread = add_labels(issue, labels, output) if labels && !labels.empty?
81
97
  set_milestone_thread = set_milestone(issue, milestone, output) if milestone
82
98
 
99
+ # same considerations as above, but with additional upstream case.
83
100
  if assignees
84
- assign_users_thread = assign_users(issue, assignees, output)
85
- else
86
- assign_users_thread = assign_authenticated_user(repository, issue, output)
101
+ assign_users_thread = assign_users(issue, assignees, output) if !assignees.empty?
102
+ elsif !@repository.upstream?
103
+ assign_users_thread = assign_authenticated_user(issue, output)
87
104
  end
88
105
 
89
106
  add_labels_thread&.join
90
107
  set_milestone_thread&.join
91
- assign_users_thread.join
108
+ assign_users_thread&.join
92
109
  end
93
110
 
94
111
  def add_labels(issue, selected_labels, output)
@@ -117,14 +134,22 @@ module Geet
117
134
  end
118
135
  end
119
136
 
120
- def assign_authenticated_user(repository, issue, output)
137
+ def assign_authenticated_user(issue, output)
121
138
  output.puts 'Assigning authenticated user...'
122
139
 
123
140
  Thread.new do
124
- issue.assign_users(repository.authenticated_user)
141
+ issue.assign_users(@repository.authenticated_user)
125
142
  end
126
143
  end
127
144
 
145
+ def save_summary(title, description, output)
146
+ summary = "#{title}\n\n#{description}".strip + "\n"
147
+
148
+ IO.write(SUMMARY_BACKUP_FILENAME, summary)
149
+
150
+ output.puts "Error! Saved summary to #{SUMMARY_BACKUP_FILENAME}"
151
+ end
152
+
128
153
  # Generic helpers
129
154
 
130
155
  def select_entries(entry_type, entries, raw_patterns, selection_type, instance_method)
@@ -3,8 +3,12 @@
3
3
  module Geet
4
4
  module Services
5
5
  class CreateLabel
6
- def execute(repository, name, color: generate_random_color, output: $stdout)
7
- label = create_label(repository, name, color, output)
6
+ def initialize(repository)
7
+ @repository = repository
8
+ end
9
+
10
+ def execute(name, color: generate_random_color, output: $stdout)
11
+ label = create_label(name, color, output)
8
12
 
9
13
  output.puts "Created with color ##{label.color}"
10
14
 
@@ -13,10 +17,10 @@ module Geet
13
17
 
14
18
  private
15
19
 
16
- def create_label(repository, name, color, output)
20
+ def create_label(name, color, output)
17
21
  output.puts 'Creating label...'
18
22
 
19
- repository.create_label(name, color)
23
+ @repository.create_label(name, color)
20
24
  end
21
25
 
22
26
  # Return a 6-digits hex random color.
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tmpdir'
3
4
  require_relative '../helpers/os_helper.rb'
4
5
  require_relative '../utils/manual_list_selection.rb'
5
6
  require_relative '../utils/pattern_matching_selection.rb'
@@ -9,28 +10,41 @@ module Geet
9
10
  class CreatePr
10
11
  include Geet::Helpers::OsHelper
11
12
 
13
+ DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
14
+
12
15
  MANUAL_LIST_SELECTION_FLAG = '-'.freeze
13
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
21
+ @git_client = git_client
22
+ end
23
+
14
24
  # options:
15
25
  # :label_patterns
16
26
  # :reviewer_patterns
17
27
  # :no_open_pr
18
28
  #
19
29
  def execute(
20
- repository, title, description, label_patterns: nil, milestone_pattern: nil, reviewer_patterns: nil,
21
- no_open_pr: nil, output: $stdout, **
30
+ title, description, label_patterns: nil, milestone_pattern: nil, reviewer_patterns: nil,
31
+ no_open_pr: nil, automated_mode: false, output: $stdout, **
22
32
  )
33
+ ensure_clean_tree if automated_mode
34
+
23
35
  all_labels, all_milestones, all_collaborators = find_all_attribute_entries(
24
- repository, label_patterns, milestone_pattern, reviewer_patterns, output
36
+ label_patterns, milestone_pattern, reviewer_patterns, output
25
37
  )
26
38
 
27
39
  labels = select_entries('label', all_labels, label_patterns, :multiple, :name) if label_patterns
28
40
  milestone, _ = select_entries('milestone', all_milestones, milestone_pattern, :single, :title) if milestone_pattern
29
- reviewers = select_entries('collaborator', all_collaborators, reviewer_patterns, :multiple, nil) if reviewer_patterns
41
+ reviewers = select_entries('reviewer', all_collaborators, reviewer_patterns, :multiple, nil) if reviewer_patterns
30
42
 
31
- pr = create_pr(repository, title, description, output)
43
+ sync_with_upstream_branch(output) if automated_mode
32
44
 
33
- edit_pr(repository, pr, labels, milestone, reviewers, output)
45
+ pr = create_pr(title, description, output)
46
+
47
+ edit_pr(pr, labels, milestone, reviewers, output)
34
48
 
35
49
  if no_open_pr
36
50
  output.puts "PR address: #{pr.link}"
@@ -39,47 +53,74 @@ module Geet
39
53
  end
40
54
 
41
55
  pr
56
+ rescue => error
57
+ save_summary(title, description, output) if title
58
+ raise
42
59
  end
43
60
 
44
61
  private
45
62
 
46
63
  # Internal actions
47
64
 
48
- def find_all_attribute_entries(repository,label_patterns, milestone_pattern, reviewer_patterns, output)
65
+ def ensure_clean_tree
66
+ raise 'The working tree is not clean!' if !@git_client.working_tree_clean?
67
+ end
68
+
69
+ def find_all_attribute_entries(label_patterns, milestone_pattern, reviewer_patterns, output)
49
70
  if label_patterns
50
71
  output.puts 'Finding labels...'
51
- labels_thread = Thread.new { repository.labels }
72
+ labels_thread = Thread.new { @repository.labels }
52
73
  end
53
74
 
54
75
  if milestone_pattern
55
76
  output.puts 'Finding milestone...'
56
- milestone_thread = Thread.new { repository.milestones }
77
+ milestone_thread = Thread.new { @repository.milestones }
57
78
  end
58
79
 
59
80
  if reviewer_patterns
60
81
  output.puts 'Finding collaborators...'
61
- reviewers_thread = Thread.new { repository.collaborators }
82
+ reviewers_thread = Thread.new { @repository.collaborators }
62
83
  end
63
84
 
64
85
  labels = labels_thread&.value
65
86
  milestones = milestone_thread&.value
66
87
  reviewers = reviewers_thread&.value
67
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
+
68
93
  [labels, milestones, reviewers]
69
94
  end
70
95
 
71
- def create_pr(repository, title, description, output)
96
+ def sync_with_upstream_branch(output)
97
+ if @git_client.upstream_branch
98
+ output.puts "Pushing to upstream branch..."
99
+
100
+ @git_client.push
101
+ else
102
+ upstream_branch = @git_client.current_branch
103
+
104
+ output.puts "Creating upstream branch #{upstream_branch.inspect}..."
105
+
106
+ @git_client.push(upstream_branch: upstream_branch)
107
+ end
108
+ end
109
+
110
+ def create_pr(title, description, output)
72
111
  output.puts 'Creating PR...'
73
112
 
74
- repository.create_pr(title, description, repository.current_branch)
113
+ @repository.create_pr(title, description, @git_client.current_branch)
75
114
  end
76
115
 
77
- def edit_pr(repository, pr, labels, milestone, reviewers, output)
78
- assign_user_thread = assign_authenticated_user(pr, repository, output)
116
+ def edit_pr(pr, labels, milestone, reviewers, output)
117
+ assign_user_thread = assign_authenticated_user(pr, output)
79
118
 
80
- add_labels_thread = add_labels(pr, labels, output) if labels
119
+ # labels/reviewers can be nil (parameter not passed) or empty array (parameter passed, but
120
+ # nothing selected)
121
+ add_labels_thread = add_labels(pr, labels, output) if labels && !labels.empty?
81
122
  set_milestone_thread = set_milestone(pr, milestone, output) if milestone
82
- request_review_thread = request_review(pr, reviewers, output) if reviewers
123
+ request_review_thread = request_review(pr, reviewers, output) if reviewers && !reviewers.empty?
83
124
 
84
125
  assign_user_thread.join
85
126
  add_labels_thread&.join
@@ -87,11 +128,11 @@ module Geet
87
128
  request_review_thread&.join
88
129
  end
89
130
 
90
- def assign_authenticated_user(pr, repository, output)
131
+ def assign_authenticated_user(pr, output)
91
132
  output.puts 'Assigning authenticated user...'
92
133
 
93
134
  Thread.new do
94
- pr.assign_users(repository.authenticated_user)
135
+ pr.assign_users(@repository.authenticated_user)
95
136
  end
96
137
  end
97
138
 
@@ -121,6 +162,14 @@ module Geet
121
162
  end
122
163
  end
123
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
+
124
173
  # Generic helpers
125
174
 
126
175
  def select_entries(entry_type, entries, raw_patterns, selection_type, instance_method)