geet 0.27.2 → 0.27.3

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -0
  3. data/Gemfile +9 -9
  4. data/Rakefile +2 -2
  5. data/bin/geet +7 -7
  6. data/geet.gemspec +19 -19
  7. data/lib/geet/commandline/commands.rb +16 -15
  8. data/lib/geet/commandline/configuration.rb +96 -92
  9. data/lib/geet/commandline/editor.rb +13 -7
  10. data/lib/geet/git/repository.rb +75 -6
  11. data/lib/geet/github/abstract_issue.rb +4 -4
  12. data/lib/geet/github/api_interface.rb +23 -23
  13. data/lib/geet/github/gist.rb +8 -8
  14. data/lib/geet/github/issue.rb +5 -5
  15. data/lib/geet/github/label.rb +4 -4
  16. data/lib/geet/github/milestone.rb +8 -8
  17. data/lib/geet/github/pr.rb +20 -20
  18. data/lib/geet/github/remote_repository.rb +1 -1
  19. data/lib/geet/github/user.rb +5 -5
  20. data/lib/geet/gitlab/api_interface.rb +13 -13
  21. data/lib/geet/gitlab/issue.rb +3 -3
  22. data/lib/geet/gitlab/label.rb +3 -3
  23. data/lib/geet/gitlab/milestone.rb +4 -4
  24. data/lib/geet/gitlab/pr.rb +3 -3
  25. data/lib/geet/gitlab/user.rb +2 -2
  26. data/lib/geet/helpers/json_helper.rb +1 -1
  27. data/lib/geet/helpers/os_helper.rb +5 -5
  28. data/lib/geet/helpers/services_workflow_helper.rb +4 -4
  29. data/lib/geet/services/abstract_create_issue.rb +3 -3
  30. data/lib/geet/services/add_upstream_repo.rb +1 -1
  31. data/lib/geet/services/close_milestones.rb +9 -2
  32. data/lib/geet/services/comment_pr.rb +11 -0
  33. data/lib/geet/services/create_gist.rb +18 -4
  34. data/lib/geet/services/create_issue.rb +13 -7
  35. data/lib/geet/services/create_label.rb +22 -3
  36. data/lib/geet/services/create_milestone.rb +7 -1
  37. data/lib/geet/services/create_pr.rb +98 -23
  38. data/lib/geet/services/list_issues.rb +4 -3
  39. data/lib/geet/services/list_labels.rb +7 -0
  40. data/lib/geet/services/list_milestones.rb +35 -6
  41. data/lib/geet/services/list_prs.rb +7 -0
  42. data/lib/geet/services/merge_pr.rb +20 -2
  43. data/lib/geet/services/open_pr.rb +2 -2
  44. data/lib/geet/services/open_repo.rb +7 -1
  45. data/lib/geet/shared/repo_permissions.rb +4 -4
  46. data/lib/geet/shared/selection.rb +2 -2
  47. data/lib/geet/utils/attributes_selection_manager.rb +30 -10
  48. data/lib/geet/utils/git_client.rb +74 -33
  49. data/lib/geet/utils/manual_list_selection.rb +23 -11
  50. data/lib/geet/utils/string_matching_selection.rb +22 -6
  51. data/lib/geet/version.rb +2 -1
  52. data/lib/geet.rb +2 -2
  53. data/spec/integration/comment_pr_spec.rb +10 -10
  54. data/spec/integration/create_gist_spec.rb +12 -12
  55. data/spec/integration/create_issue_spec.rb +21 -21
  56. data/spec/integration/create_label_spec.rb +33 -33
  57. data/spec/integration/create_milestone_spec.rb +9 -9
  58. data/spec/integration/create_pr_spec.rb +120 -134
  59. data/spec/integration/list_issues_spec.rb +25 -25
  60. data/spec/integration/list_labels_spec.rb +15 -15
  61. data/spec/integration/list_milestones_spec.rb +15 -15
  62. data/spec/integration/list_prs_spec.rb +10 -10
  63. data/spec/integration/merge_pr_spec.rb +18 -18
  64. data/spec/integration/open_pr_spec.rb +18 -20
  65. data/spec/integration/open_repo_spec.rb +18 -18
  66. data/spec/spec_helper.rb +10 -10
  67. data/spec/unit/github/pr_spec.rb +73 -73
  68. metadata +3 -3
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
  # typed: strict
3
3
 
4
- require 'cgi'
5
- require 'uri'
6
- require 'net/http'
7
- require 'json'
4
+ require "cgi"
5
+ require "uri"
6
+ require "net/http"
7
+ require "json"
8
8
 
9
9
  module Geet
10
10
  module Gitlab
11
11
  class ApiInterface
12
12
  extend T::Sig
13
13
 
14
- API_BASE_URL = 'https://gitlab.com/api/v4'
14
+ API_BASE_URL = "https://gitlab.com/api/v4"
15
15
 
16
16
  sig { returns(T.nilable(String)) }
17
17
  attr_reader :repository_path
@@ -126,7 +126,7 @@ module Geet
126
126
  Net::HTTP.start(uri.host, use_ssl: true) do |http|
127
127
  request = http_class.new(uri)
128
128
 
129
- request['Private-Token'] = @api_token
129
+ request["Private-Token"] = @api_token
130
130
  request.body = URI.encode_www_form(data) if data
131
131
 
132
132
  http.request(request)
@@ -140,7 +140,7 @@ module Geet
140
140
  ).returns(URI::Generic)
141
141
  }
142
142
  def encode_uri(address, params)
143
- address += '?' + URI.encode_www_form(params) if params
143
+ address += "?" + URI.encode_www_form(params) if params
144
144
 
145
145
  URI(address)
146
146
  end
@@ -151,7 +151,7 @@ module Geet
151
151
  ).returns(T::Boolean)
152
152
  }
153
153
  def error?(response)
154
- !response.code.start_with?('2')
154
+ !response.code.start_with?("2")
155
155
  end
156
156
 
157
157
  sig {
@@ -160,10 +160,10 @@ module Geet
160
160
  ).returns(String)
161
161
  }
162
162
  def decode_and_format_error(parsed_response)
163
- if parsed_response.key?('error')
164
- parsed_response.fetch('error')
165
- elsif parsed_response.key?('message')
166
- parsed_response.fetch('message')
163
+ if parsed_response.key?("error")
164
+ parsed_response.fetch("error")
165
+ elsif parsed_response.key?("message")
166
+ parsed_response.fetch("message")
167
167
  else
168
168
  "Unrecognized response: #{parsed_response}"
169
169
  end
@@ -176,7 +176,7 @@ module Geet
176
176
  }
177
177
  def link_next_page(response_headers)
178
178
  # An array (or nil) is returned.
179
- link_header = Array(response_headers['link'])
179
+ link_header = Array(response_headers["link"])
180
180
 
181
181
  return nil if link_header.empty?
182
182
 
@@ -50,9 +50,9 @@ module Geet
50
50
  )
51
51
 
52
52
  response.map do |issue_data, result|
53
- number = T.cast(issue_data.fetch('iid'), Integer)
54
- title = T.cast(issue_data.fetch('title'), String)
55
- link = T.cast(issue_data.fetch('web_url'), String)
53
+ number = T.cast(issue_data.fetch("iid"), Integer)
54
+ title = T.cast(issue_data.fetch("title"), String)
55
+ link = T.cast(issue_data.fetch("web_url"), String)
56
56
 
57
57
  new(number, title, link)
58
58
  end
@@ -36,10 +36,10 @@ module Geet
36
36
  )
37
37
 
38
38
  response.map do |label_entry|
39
- name = T.cast(label_entry.fetch('name'), String)
40
- color = T.cast(label_entry.fetch('color'), String)
39
+ name = T.cast(label_entry.fetch("name"), String)
40
+ color = T.cast(label_entry.fetch("color"), String)
41
41
 
42
- color = color.sub('#', '') # normalize
42
+ color = color.sub("#", "") # normalize
43
43
 
44
44
  new(name, color)
45
45
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # typed: strict
3
3
 
4
- require 'date'
4
+ require "date"
5
5
 
6
6
  module Geet
7
7
  module Gitlab
@@ -49,10 +49,10 @@ module Geet
49
49
  )
50
50
 
51
51
  response.map do |milestone_data|
52
- number = T.cast(milestone_data.fetch('iid'), Integer)
53
- title = T.cast(milestone_data.fetch('title'), String)
52
+ number = T.cast(milestone_data.fetch("iid"), Integer)
53
+ title = T.cast(milestone_data.fetch("title"), String)
54
54
  due_on = parse_due_date(
55
- T.cast(milestone_data.fetch('due_date'), T.nilable(String))
55
+ T.cast(milestone_data.fetch("due_date"), T.nilable(String))
56
56
  )
57
57
 
58
58
  new(number, title, due_on, api_interface)
@@ -59,9 +59,9 @@ module Geet
59
59
  )
60
60
 
61
61
  response.map do |issue_data, result|
62
- number = T.cast(issue_data.fetch('iid'), Integer)
63
- title = T.cast(issue_data.fetch('title'), String)
64
- link = T.cast(issue_data.fetch('web_url'), String)
62
+ number = T.cast(issue_data.fetch("iid"), Integer)
63
+ title = T.cast(issue_data.fetch("title"), String)
64
+ link = T.cast(issue_data.fetch("web_url"), String)
65
65
 
66
66
  new(number, api_interface, title, link)
67
67
  end
@@ -41,8 +41,8 @@ module Geet
41
41
  )
42
42
 
43
43
  response.map do |user_entry|
44
- id = T.cast(user_entry.fetch('id'), Integer)
45
- username = T.cast(user_entry.fetch('username'), String)
44
+ id = T.cast(user_entry.fetch("id"), Integer)
45
+ username = T.cast(user_entry.fetch("username"), String)
46
46
 
47
47
  new(id, username, api_interface)
48
48
  end
@@ -1,7 +1,7 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'time'
4
+ require "time"
5
5
 
6
6
  module Geet
7
7
  module Helpers
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  # typed: true
3
3
 
4
- require 'English'
5
- require 'open3'
6
- require 'shellwords'
4
+ require "English"
5
+ require "open3"
6
+ require "shellwords"
7
7
 
8
8
  module Geet
9
9
  module Helpers
@@ -17,7 +17,7 @@ module Geet
17
17
  open_command = case
18
18
  when ENV["WSL_DISTRO_NAME"]
19
19
  "wslview"
20
- when `uname`.strip == 'Darwin'
20
+ when `uname`.strip == "Darwin"
21
21
  "open"
22
22
  else
23
23
  "xdg-open"
@@ -61,7 +61,7 @@ module Geet
61
61
  stdout_content = stdout.read
62
62
  stderr_content = stderr.read
63
63
 
64
- puts stderr_content if stderr_content != '' && !silent_stderr
64
+ puts stderr_content if stderr_content != "" && !silent_stderr
65
65
 
66
66
  if !wait_thread.value.success? && !allow_error
67
67
  error_message = stderr_content.lines.first&.strip || "Error running command #{command.inspect}"
@@ -1,9 +1,9 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'English'
5
- require 'open3'
6
- require 'shellwords'
4
+ require "English"
5
+ require "open3"
6
+ require "shellwords"
7
7
 
8
8
  module Geet
9
9
  module Helpers
@@ -40,7 +40,7 @@ module Geet
40
40
 
41
41
  raise "Expected to find only one PR for the current branch; found: #{prs.size}" if prs.size != 1
42
42
 
43
- prs[0]
43
+ T.must(prs[0])
44
44
  end
45
45
  end
46
46
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  # typed: strict
3
3
 
4
- require 'stringio'
5
- require 'tmpdir'
4
+ require "stringio"
5
+ require "tmpdir"
6
6
 
7
7
  module Geet
8
8
  module Services
@@ -11,7 +11,7 @@ module Geet
11
11
 
12
12
  include Geet::Helpers::OsHelper
13
13
 
14
- sig { params(repository: T.untyped, out: T.any(IO, StringIO)).void }
14
+ sig { params(repository: Git::Repository, out: T.any(IO, StringIO)).void }
15
15
  def initialize(repository, out: $stdout)
16
16
  @repository = repository
17
17
  @out = out
@@ -10,7 +10,7 @@ module Geet
10
10
 
11
11
  DEFAULT_GIT_CLIENT = Utils::GitClient.new
12
12
 
13
- sig { params(repository: T.untyped, out: T.any(IO, StringIO), git_client: T.untyped).void }
13
+ sig { params(repository: Git::Repository, out: T.any(IO, StringIO), git_client: Utils::GitClient).void }
14
14
  def initialize(repository, out: $stdout, git_client: DEFAULT_GIT_CLIENT)
15
15
  @repository = repository
16
16
  @out = out
@@ -1,15 +1,20 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
4
  module Geet
4
5
  module Services
5
6
  class CloseMilestones
7
+ extend T::Sig
8
+
6
9
  include Geet::Shared::Selection
7
10
 
11
+ sig { params(repository: Git::Repository, out: T.any(IO, StringIO)).void }
8
12
  def initialize(repository, out: $stdout)
9
13
  @repository = repository
10
14
  @out = out
11
15
  end
12
16
 
17
+ sig { params(numbers: T.nilable(String)).void }
13
18
  def execute(numbers: nil)
14
19
  numbers = find_and_select_milestone_numbers(numbers)
15
20
 
@@ -20,16 +25,18 @@ module Geet
20
25
 
21
26
  private
22
27
 
28
+ sig { params(numbers: T.nilable(String)).returns(T::Array[Integer]) }
23
29
  def find_and_select_milestone_numbers(numbers)
24
30
  selection_manager = Geet::Utils::AttributesSelectionManager.new(@repository, out: @out)
25
31
 
26
- selection_manager.add_attribute(:milestones, 'milestone', numbers, SELECTION_MULTIPLE, name_method: :title)
32
+ selection_manager.add_attribute(:milestones, "milestone", numbers, SELECTION_MULTIPLE, name_method: :title)
27
33
 
28
- milestones = selection_manager.select_attributes[0]
34
+ milestones = T.cast(selection_manager.select_attributes[0], T::Array[T.any(Github::Milestone, Gitlab::Milestone)])
29
35
 
30
36
  milestones.map(&:number)
31
37
  end
32
38
 
39
+ sig { params(numbers: T::Array[Integer]).returns(T::Array[Thread]) }
33
40
  def close_milestones(numbers)
34
41
  @out.puts "Closing milestones #{numbers.join(', ')}..."
35
42
 
@@ -1,21 +1,32 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
4
  module Geet
4
5
  module Services
5
6
  # Add a comment to the PR for the current branch.
6
7
  #
7
8
  class CommentPr
9
+ extend T::Sig
10
+
8
11
  include Geet::Helpers::OsHelper
9
12
  include Geet::Helpers::ServicesWorkflowHelper
10
13
 
11
14
  DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
12
15
 
16
+ sig { params(repository: Git::Repository, out: T.any(IO, StringIO), git_client: Utils::GitClient).void }
13
17
  def initialize(repository, out: $stdout, git_client: DEFAULT_GIT_CLIENT)
14
18
  @repository = repository
15
19
  @out = out
16
20
  @git_client = git_client
17
21
  end
18
22
 
23
+ sig {
24
+ params(
25
+ comment: String,
26
+ open_browser: T::Boolean
27
+ )
28
+ .returns(T.any(Github::PR, Gitlab::PR))
29
+ }
19
30
  def execute(comment, open_browser: false)
20
31
  pr = checked_find_branch_pr
21
32
  pr.comment(comment)
@@ -1,18 +1,22 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
4
  module Geet
4
5
  module Services
5
6
  class CreateGist
7
+ extend T::Sig
8
+
6
9
  include Geet::Helpers::OsHelper
7
10
 
8
- API_TOKEN_KEY = 'GITHUB_API_TOKEN'
11
+ API_TOKEN_KEY = "GITHUB_API_TOKEN"
9
12
  DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
10
13
 
14
+ sig { params(out: T.any(IO, StringIO)).void }
11
15
  def initialize(out: $stdout)
12
- @out = out
16
+ @out = T.let(out, T.any(IO, StringIO))
13
17
 
14
18
  api_token = extract_env_api_token
15
- @api_interface = Geet::Github::ApiInterface.new(api_token)
19
+ @api_interface = T.let(Geet::Github::ApiInterface.new(api_token), Geet::Github::ApiInterface)
16
20
  end
17
21
 
18
22
  # options:
@@ -20,10 +24,19 @@ module Geet
20
24
  # :publik: defaults to false
21
25
  # :open_browser defaults to true
22
26
  #
27
+ sig {
28
+ params(
29
+ full_filename: String,
30
+ stdin: T::Boolean,
31
+ description: T.nilable(String),
32
+ publik: T::Boolean,
33
+ open_browser: T::Boolean
34
+ ).void
35
+ }
23
36
  def execute(full_filename, stdin: false, description: nil, publik: false, open_browser: false)
24
37
  content = stdin ? $stdin.read : IO.read(full_filename)
25
38
 
26
- gist_access = publik ? 'public' : 'private'
39
+ gist_access = publik ? "public" : "private"
27
40
  @out.puts "Creating a #{gist_access} gist..."
28
41
 
29
42
  filename = File.basename(full_filename)
@@ -38,6 +51,7 @@ module Geet
38
51
 
39
52
  private
40
53
 
54
+ sig { returns(String) }
41
55
  def extract_env_api_token
42
56
  ENV[API_TOKEN_KEY] || raise("#{API_TOKEN_KEY} not set!")
43
57
  end
@@ -68,11 +68,17 @@ module Geet
68
68
  def find_and_select_attributes(labels, milestone, assignees)
69
69
  selection_manager = Geet::Utils::AttributesSelectionManager.new(@repository, out: @out)
70
70
 
71
- selection_manager.add_attribute(:labels, 'label', labels, SELECTION_MULTIPLE, name_method: :name) if labels
72
- selection_manager.add_attribute(:milestones, 'milestone', milestone, SELECTION_SINGLE, name_method: :title) if milestone
73
- selection_manager.add_attribute(:collaborators, 'assignee', assignees, SELECTION_MULTIPLE, name_method: :username) if assignees
71
+ selection_manager.add_attribute(:labels, "label", labels, SELECTION_MULTIPLE, name_method: :name) if labels
72
+ selection_manager.add_attribute(:milestones, "milestone", milestone, SELECTION_SINGLE, name_method: :title) if milestone
73
+ selection_manager.add_attribute(:collaborators, "assignee", assignees, SELECTION_MULTIPLE, name_method: :username) if assignees
74
74
 
75
- selection_manager.select_attributes
75
+ selected_attributes = selection_manager.select_attributes
76
+
77
+ selected_labels = T.cast(selected_attributes.shift, T.nilable(T::Array[T.any(Github::Label, Gitlab::Label)])) if labels
78
+ selected_milestone = T.cast(selected_attributes.shift, T.nilable(T.any(Github::Milestone, Gitlab::Milestone))) if milestone
79
+ selected_assignees = T.cast(selected_attributes.shift, T.nilable(T::Array[T.any(Github::User, Gitlab::User)])) if assignees
80
+
81
+ [selected_labels, selected_milestone, selected_assignees]
76
82
  end
77
83
 
78
84
  sig {
@@ -82,7 +88,7 @@ module Geet
82
88
  ).returns(T.any(Github::Issue, Gitlab::Issue))
83
89
  }
84
90
  def create_issue(title, description)
85
- @out.puts 'Creating the issue...'
91
+ @out.puts "Creating the issue..."
86
92
 
87
93
  issue = @repository.create_issue(title, description)
88
94
  end
@@ -122,7 +128,7 @@ module Geet
122
128
  def add_labels(issue, selected_labels)
123
129
  raise "Functionality unsupported on GitLab!" if issue.is_a?(Gitlab::Issue)
124
130
 
125
- labels_list = selected_labels.map(&:name).join(', ')
131
+ labels_list = selected_labels.map(&:name).join(", ")
126
132
 
127
133
  @out.puts "Adding labels #{labels_list}..."
128
134
 
@@ -173,7 +179,7 @@ module Geet
173
179
  def assign_authenticated_user(issue)
174
180
  raise "Functionality unsupported on GitLab!" if issue.is_a?(Gitlab::Issue)
175
181
 
176
- @out.puts 'Assigning authenticated user...'
182
+ @out.puts "Assigning authenticated user..."
177
183
 
178
184
  Thread.new do
179
185
  issue.assign_users(@repository.authenticated_user.username)
@@ -1,13 +1,24 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
4
  module Geet
4
5
  module Services
5
6
  class CreateLabel
7
+ extend T::Sig
8
+
9
+ sig { params(repository: Git::Repository, out: T.any(IO, StringIO)).void }
6
10
  def initialize(repository, out: $stdout)
7
11
  @repository = repository
8
12
  @out = out
9
13
  end
10
14
 
15
+ sig {
16
+ params(
17
+ name: String,
18
+ color: String
19
+ )
20
+ .returns(T.any(Github::Label, Gitlab::Label))
21
+ }
11
22
  def execute(name, color: generate_random_color)
12
23
  label = create_label(name, color)
13
24
 
@@ -18,17 +29,25 @@ module Geet
18
29
 
19
30
  private
20
31
 
32
+ sig {
33
+ params(
34
+ name: String,
35
+ color: String
36
+ )
37
+ .returns(T.any(Github::Label, Gitlab::Label))
38
+ }
21
39
  def create_label(name, color)
22
- @out.puts 'Creating label...'
40
+ @out.puts "Creating label..."
23
41
 
24
42
  @repository.create_label(name, color)
25
43
  end
26
44
 
27
45
  # Return a 6-digits hex random color.
46
+ sig { returns(String) }
28
47
  def generate_random_color
29
- hex_number = rand(2**24).to_s(16)
48
+ hex_number = T.unsafe(rand(2**24)).to_s(16)
30
49
 
31
- hex_number.rjust(6, '0')
50
+ hex_number.rjust(6, "0")
32
51
  end
33
52
  end
34
53
  end
@@ -1,21 +1,27 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
4
  module Geet
4
5
  module Services
5
6
  class CreateMilestone
7
+ extend T::Sig
8
+
9
+ sig { params(repository: Git::Repository, out: T.any(IO, StringIO)).void }
6
10
  def initialize(repository, out: $stdout)
7
11
  @repository = repository
8
12
  @out = out
9
13
  end
10
14
 
15
+ sig { params(title: String).returns(T.any(Github::Milestone, Gitlab::Milestone)) }
11
16
  def execute(title)
12
17
  create_milestone(title)
13
18
  end
14
19
 
15
20
  private
16
21
 
22
+ sig { params(title: String).returns(T.any(Github::Milestone, Gitlab::Milestone)) }
17
23
  def create_milestone(title)
18
- @out.puts 'Creating milestone...'
24
+ @out.puts "Creating milestone..."
19
25
 
20
26
  @repository.create_milestone(title)
21
27
  end