geet 0.3.0 → 0.3.1

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 (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)