geet 0.23.0 → 0.25.0

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +31 -4
  3. data/.gitignore +0 -1
  4. data/.ruby-version +1 -0
  5. data/Gemfile +3 -6
  6. data/bin/geet +2 -8
  7. data/geet.gemspec +4 -4
  8. data/lib/geet/commandline/configuration.rb +1 -1
  9. data/lib/geet/commandline/editor.rb +0 -2
  10. data/lib/geet/git/repository.rb +12 -21
  11. data/lib/geet/github/abstract_issue.rb +0 -6
  12. data/lib/geet/github/api_interface.rb +37 -1
  13. data/lib/geet/github/issue.rb +0 -3
  14. data/lib/geet/github/milestone.rb +0 -2
  15. data/lib/geet/github/pr.rb +31 -4
  16. data/lib/geet/github/user.rb +0 -3
  17. data/lib/geet/gitlab/pr.rb +3 -1
  18. data/lib/geet/helpers/json_helper.rb +4 -0
  19. data/lib/geet/helpers/os_helper.rb +21 -7
  20. data/lib/geet/helpers/services_workflow_helper.rb +12 -0
  21. data/lib/geet/helpers/summary_helper.rb +7 -0
  22. data/lib/geet/services/abstract_create_issue.rb +5 -5
  23. data/lib/geet/services/add_upstream_repo.rb +6 -0
  24. data/lib/geet/services/close_milestones.rb +0 -2
  25. data/lib/geet/services/comment_pr.rb +0 -3
  26. data/lib/geet/services/create_gist.rb +0 -4
  27. data/lib/geet/services/create_issue.rb +0 -4
  28. data/lib/geet/services/create_pr.rb +24 -7
  29. data/lib/geet/services/list_issues.rb +0 -3
  30. data/lib/geet/services/merge_pr.rb +0 -2
  31. data/lib/geet/services/open_pr.rb +0 -3
  32. data/lib/geet/services/open_repo.rb +0 -2
  33. data/lib/geet/shared/http_error.rb +8 -2
  34. data/lib/geet/shared/repo_permissions.rb +7 -2
  35. data/lib/geet/shared/selection.rb +3 -2
  36. data/lib/geet/utils/attributes_selection_manager.rb +15 -4
  37. data/lib/geet/utils/git_client.rb +4 -1
  38. data/lib/geet/utils/manual_list_selection.rb +39 -14
  39. data/lib/geet/utils/string_matching_selection.rb +5 -0
  40. data/lib/geet/version.rb +1 -1
  41. data/lib/geet.rb +11 -0
  42. data/sorbet/config +3 -1
  43. data/sorbet/rbi/gems/{rbs@3.9.5.rbi → rbs@4.0.0.dev.5.rbi} +2013 -680
  44. data/sorbet/rbi/gems/require-hooks@0.2.2.rbi +110 -0
  45. data/sorbet/rbi/gems/{spoom@1.6.3.rbi → spoom@1.7.11.rbi} +1139 -2246
  46. data/sorbet/rbi/gems/{tapioca@0.16.11.rbi → tapioca@0.17.10.rbi} +721 -835
  47. data/sorbet/rbi/gems/tsort@0.2.0.rbi +393 -0
  48. data/sorbet/rbi/gems/tty-prompt@0.23.1.rbi +3300 -2
  49. data/sorbet/rbi/gems/zeitwerk@2.7.4.rbi +1196 -0
  50. data/sorbet/rbi/shims/unresolved_gem_constants.rbi +4 -0
  51. data/spec/integration/create_pr_spec.rb +225 -147
  52. data/spec/integration/merge_pr_spec.rb +84 -85
  53. data/spec/spec_helper.rb +1 -1
  54. metadata +40 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f36daf3a9f93bc19c635672aa0dacd0c661680aff4ab62042c7bb9743d9283c0
4
- data.tar.gz: 43eb3b1315136af98b85d828f352ae8b7556cc5049bf2d23e8d4b2396728027e
3
+ metadata.gz: 8f33191668d757cda4abaccb0524277d39923df81e1c17e7175fd6ccd27e0751
4
+ data.tar.gz: 0650f891e46a6c108cd59fd91cae1a396214dda38497eefa1cc6712df42b8971
5
5
  SHA512:
6
- metadata.gz: 10993b5f5d10122cf60ac37de56600bd5ea131b82cfb78e40cd468a56b34eba3b2f101ee1ec8bb8b78c3d419c5a9569006d1bec2be01bbc78e6d2fed80a1eab9
7
- data.tar.gz: fedbbf26a35167056c4c1bb0800aa9f233174ab2b850ff8467c27bdec3b5ae79c0c3258983b5e5ea3efb4739516cd97e634c70f35ad0b627e38ed9624b95485f
6
+ metadata.gz: 6748bd9048d5d828bf30e356d134c37f607370102792408535717f97e1a46938e59078c4f331173634e4e694ca05b68b8ae6d19464d02c19493533bc3a52b4fa
7
+ data.tar.gz: 1c27b254f20de196d7e74de519cc47358b9a0c2daf3fe565e7f593b8af6dae109dbab066015eda103c9599480ad1231b5e9b4318c96a3578bb15b002b7e82d17
@@ -3,18 +3,45 @@ name: CI
3
3
  on: [pull_request]
4
4
 
5
5
  jobs:
6
- test:
6
+ test_suite:
7
+ name: Test Suite
7
8
  runs-on: ubuntu-latest
9
+ env:
10
+ GITHUB_API_TOKEN: foo
11
+ GITLAB_API_TOKEN: bar
8
12
  strategy:
9
13
  matrix:
10
- ruby-version: [head, 3.4, 3.3, 3.2]
14
+ ruby-version: [head, 4.0, 3.4, 3.3, 3.2]
11
15
  fail-fast: false
12
- continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
16
+ continue-on-error: ${{ endsWith(matrix['ruby-version'], 'head') }}
13
17
  steps:
14
- - uses: actions/checkout@v5
18
+ - uses: actions/checkout@v6
15
19
  - uses: ruby/setup-ruby@v1
16
20
  with:
17
21
  ruby-version: ${{ matrix.ruby-version }}
18
22
  bundler-cache: true
19
23
  - run: bundle install
20
24
  - run: bundle exec rspec
25
+ sorbet:
26
+ name: Sorbet typecheck
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v6
30
+ with:
31
+ fetch-depth: ${{ env.REPO_FETCH_DEPTH }}
32
+ - uses: ruby/setup-ruby@v1
33
+ with:
34
+ bundler-cache: true
35
+ - name: Sorbet
36
+ run: bundle exec srb typecheck
37
+ # Ruby summary job, for branch protection rules
38
+ # Head ruby failures are ignored due to continue-on-error in the test job.
39
+ all-tests:
40
+ name: Ruby (non-head) tests passed
41
+ runs-on: ubuntu-latest
42
+ needs: [test_suite]
43
+ if: always()
44
+ steps:
45
+ - name: Check test suite results
46
+ run: |
47
+ [[ "${{ needs.test_suite.result }}" == "success" ]] || exit 1
data/.gitignore CHANGED
@@ -1,4 +1,3 @@
1
- /.ruby-version
2
1
  /.ruby-gemset
3
2
  /Gemfile.lock
4
3
  /test_repos
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.6
data/Gemfile CHANGED
@@ -4,18 +4,15 @@ source 'https://rubygems.org'
4
4
 
5
5
  gemspec
6
6
 
7
- gem 'sorbet-runtime'
8
-
9
7
  group :development do
10
- gem 'sorbet'
11
8
  gem 'byebug'
12
- gem 'rubocop', '~> 1.35.0', require: :false
9
+ gem 'rubocop', '~> 1.35.0', require: false
13
10
  gem 'spoom', require: false
14
- gem 'tapioca', require: false
11
+ gem 'tapioca', '>= 0.17.10', require: false
15
12
  end
16
13
 
17
14
  group :test do
18
15
  gem 'rspec', '~> 3.13.0'
19
- gem 'vcr', '~> 6.1.0'
16
+ gem 'vcr', '~> 6.4.0'
20
17
  gem 'webmock', '~> 3.1.1'
21
18
  end
data/bin/geet CHANGED
@@ -2,14 +2,8 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'simple_scripting/configuration'
5
- require_relative '../lib/geet/commandline/configuration'
6
- require_relative '../lib/geet/commandline/commands'
7
- require_relative '../lib/geet/commandline/editor'
8
- require_relative '../lib/geet/git/repository'
9
- require_relative '../lib/geet/helpers/summary_helper'
10
- require_relative '../lib/geet/shared/selection'
11
- require_relative '../lib/geet/utils/git_client'
12
- Dir[File.join(__dir__, '../lib/geet/services/*.rb')].each { |filename| require filename }
5
+ require 'tmpdir'
6
+ require_relative '../lib/geet'
13
7
 
14
8
  class GeetLauncher
15
9
  include Geet
data/geet.gemspec CHANGED
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $LOAD_PATH << File.expand_path('lib', __dir__)
4
-
5
- require 'geet/version'
3
+ require_relative 'lib/geet/version'
6
4
 
7
5
  Gem::Specification.new do |s|
8
6
  s.name = 'geet'
@@ -10,7 +8,7 @@ Gem::Specification.new do |s|
10
8
  s.platform = Gem::Platform::RUBY
11
9
  s.required_ruby_version = '>= 3.2.0'
12
10
  s.authors = ['Saverio Miroddi']
13
- s.date = '2025-10-29'
11
+ s.date = '2026-01-13'
14
12
  s.email = ['saverio.pub2@gmail.com']
15
13
  s.homepage = 'https://github.com/saveriomiroddi/geet'
16
14
  s.summary = 'Commandline interface for performing SCM host operations, eg. create a PR on GitHub'
@@ -20,7 +18,9 @@ Gem::Specification.new do |s|
20
18
  s.add_runtime_dependency 'base64', '~> 0.3.0'
21
19
  s.add_runtime_dependency 'ostruct', '~> 0.6.3'
22
20
  s.add_runtime_dependency 'simple_scripting', '~> 0.14.0'
21
+ s.add_runtime_dependency 'sorbet-runtime', '= 0.6.12883'
23
22
  s.add_runtime_dependency 'tty-prompt', '~> 0.23.1'
23
+ s.add_runtime_dependency 'zeitwerk', '~> 2.7'
24
24
 
25
25
  s.add_development_dependency 'rake', '~> 12.3'
26
26
 
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'simple_scripting/argv'
4
- require_relative 'commands'
5
4
 
6
5
  module Geet
7
6
  module Commandline
@@ -67,6 +66,7 @@ module Geet
67
66
  ]
68
67
 
69
68
  PR_CREATE_OPTIONS = [
69
+ ['-a', '--automerge', "Enable automerge (with default strategy)"],
70
70
  ['-o', '--open-browser', "Don't open the PR link in the browser after creation"],
71
71
  ['-b', '--base develop', "Specify the base branch; defaults to the main branch"],
72
72
  ['-d', '--draft', "Create as draft"],
@@ -2,8 +2,6 @@
2
2
 
3
3
  require 'tempfile'
4
4
 
5
- require_relative '../helpers/os_helper'
6
-
7
5
  module Geet
8
6
  module Commandline
9
7
  class Editor
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../utils/git_client'
4
-
5
3
  module Geet
6
4
  module Git
7
5
  # This class represents, for convenience, both the local and the remote repository, but the
@@ -122,31 +120,24 @@ module Geet
122
120
  def attempt_provider_call(class_name, meth, *args)
123
121
  module_name = provider_name.capitalize
124
122
 
125
- require_provider_modules
126
-
127
123
  full_class_name = "Geet::#{module_name}::#{class_name}"
128
124
 
129
- if Kernel.const_defined?(full_class_name)
130
- klass = Kernel.const_get(full_class_name)
131
-
132
- if !klass.respond_to?(meth)
133
- raise "The functionality invoked (#{class_name}.#{meth}) is not currently supported!"
134
- end
135
-
136
- # Can't use ruby2_keywords, because the method definitions use named keyword arguments.
137
- #
138
- kwargs = args.last.is_a?(Hash) ? args.pop : {}
139
-
140
- klass.send(meth, *args, **kwargs)
141
- else
125
+ # Use const_get directly to trigger Zeitwerk autoloading
126
+ begin
127
+ klass = Object.const_get(full_class_name)
128
+ rescue NameError
142
129
  raise "The class referenced (#{full_class_name}) is not currently supported!"
143
130
  end
144
- end
145
131
 
146
- def require_provider_modules
147
- files_pattern = "#{__dir__}/../#{provider_name}/*.rb"
132
+ if !klass.respond_to?(meth)
133
+ raise "The functionality invoked (#{class_name}.#{meth}) is not currently supported!"
134
+ end
135
+
136
+ # Can't use ruby2_keywords, because the method definitions use named keyword arguments.
137
+ #
138
+ kwargs = args.last.is_a?(Hash) ? args.pop : {}
148
139
 
149
- Dir[files_pattern].each { |filename| require filename }
140
+ klass.send(meth, *args, **kwargs)
150
141
  end
151
142
 
152
143
  # WARNINGS
@@ -2,12 +2,6 @@
2
2
 
3
3
  module Geet
4
4
  module Github
5
- # It seems that autoloading will be deprecated, but it's currently the cleanest solution
6
- # to the legitimate problem of AbstractIssue needing Issue/PR to be loaded (due to :list),
7
- # and viceversa (due to class definition).
8
- autoload :Issue, File.expand_path('issue', __dir__)
9
- autoload :PR, File.expand_path('pr', __dir__)
10
-
11
5
  # For clarity, in this class we keep only the identical logic between the subclasses, but
12
6
  # other methods could be moved in here at some complexity cost.
13
7
  class AbstractIssue
@@ -3,13 +3,13 @@
3
3
  require 'uri'
4
4
  require 'net/http'
5
5
  require 'json'
6
- require_relative '../shared/http_error'
7
6
 
8
7
  module Geet
9
8
  module Github
10
9
  class ApiInterface
11
10
  API_AUTH_USER = '' # We don't need the login, as the API key uniquely identifies the user
12
11
  API_BASE_URL = 'https://api.github.com'
12
+ GRAPHQL_API_URL = 'https://api.github.com/graphql'
13
13
 
14
14
  attr_reader :repository_path
15
15
 
@@ -70,6 +70,42 @@ module Geet
70
70
  end
71
71
  end
72
72
 
73
+ # Send a GraphQL request.
74
+ #
75
+ # Returns the parsed response data.
76
+ #
77
+ # params:
78
+ # :query: GraphQL query string
79
+ # :variables: (Hash) GraphQL variables
80
+ #
81
+ def send_graphql_request(query, variables: {})
82
+ uri = URI(GRAPHQL_API_URL)
83
+
84
+ Net::HTTP.start(uri.host, use_ssl: true) do |http|
85
+ request = Net::HTTP::Post.new(uri).tap do
86
+ it.basic_auth API_AUTH_USER, @api_token
87
+ it['Accept'] = 'application/vnd.github.v3+json'
88
+ it.body = {query:, variables:}.to_json
89
+ end
90
+
91
+ response = http.request(request)
92
+
93
+ parsed_response = JSON.parse(response.body) if response.body
94
+
95
+ if error?(response)
96
+ error_message = decode_and_format_error(parsed_response)
97
+ raise Geet::Shared::HttpError.new(error_message, response.code)
98
+ end
99
+
100
+ if parsed_response&.key?('errors')
101
+ error_messages = parsed_response['errors'].map { |err| err['message'] }.join(', ')
102
+ raise Geet::Shared::HttpError.new("GraphQL errors: #{error_messages}", response.code)
103
+ end
104
+
105
+ parsed_response&.fetch('data')
106
+ end
107
+ end
108
+
73
109
  private
74
110
 
75
111
  def api_url(api_path)
@@ -2,9 +2,6 @@
2
2
 
3
3
  module Geet
4
4
  module Github
5
- # See AbstractIssue for the circular dependency issue notes.
6
- autoload :AbstractIssue, File.expand_path('abstract_issue', __dir__)
7
-
8
5
  class Issue < Geet::Github::AbstractIssue
9
6
  def self.create(title, description, api_interface, **)
10
7
  api_path = 'issues'
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../helpers/json_helper'
4
-
5
3
  module Geet
6
4
  module Github
7
5
  class Milestone
@@ -2,10 +2,14 @@
2
2
 
3
3
  module Geet
4
4
  module Github
5
- # See AbstractIssue for the circular dependency issue notes.
6
- autoload :AbstractIssue, File.expand_path('abstract_issue', __dir__)
7
-
8
5
  class PR < AbstractIssue
6
+ attr_reader :node_id
7
+
8
+ def initialize(number, api_interface, title, link, node_id: nil)
9
+ super(number, api_interface, title, link)
10
+ @node_id = node_id
11
+ end
12
+
9
13
  # See https://developer.github.com/v3/pulls/#create-a-pull-request
10
14
  #
11
15
  def self.create(title, description, head, api_interface, base, draft: false)
@@ -21,8 +25,9 @@ module Geet
21
25
  response = api_interface.send_request(api_path, data: request_data)
22
26
 
23
27
  number, title, link = response.fetch_values('number', 'title', 'html_url')
28
+ node_id = response['node_id']
24
29
 
25
- new(number, api_interface, title, link)
30
+ new(number, api_interface, title, link, node_id:)
26
31
  end
27
32
 
28
33
  # See https://developer.github.com/v3/pulls/#list-pull-requests
@@ -86,6 +91,28 @@ module Geet
86
91
  @api_interface.send_request(api_path, data: request_data)
87
92
  end
88
93
 
94
+ # Enable auto-merge for this PR using the repository's default merge method.
95
+ # See https://docs.github.com/en/graphql/reference/mutations#enablepullrequestautomerge
96
+ #
97
+ def enable_automerge
98
+ query = <<~GRAPHQL
99
+ mutation($pullRequestId: ID!) {
100
+ enablePullRequestAutoMerge(input: {pullRequestId: $pullRequestId}) {
101
+ pullRequest {
102
+ id
103
+ autoMergeRequest {
104
+ enabledAt
105
+ }
106
+ }
107
+ }
108
+ }
109
+ GRAPHQL
110
+
111
+ variables = { pullRequestId: @node_id }
112
+
113
+ @api_interface.send_graphql_request(query, variables:)
114
+ end
115
+
89
116
  class << self
90
117
  private
91
118
 
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../shared/repo_permissions'
4
- require_relative '../shared/http_error'
5
-
6
3
  module Geet
7
4
  module Github
8
5
  class User
@@ -40,7 +40,9 @@ module Geet
40
40
 
41
41
  # See https://docs.gitlab.com/ee/api/merge_requests.html#accept-mr
42
42
  #
43
- def merge
43
+ def merge(merge_method: nil)
44
+ raise ArgumentError, "GitLab does not support the merge_method parameter" if merge_method
45
+
44
46
  api_path = "projects/#{@api_interface.path_with_namespace(encoded: true)}/merge_requests/#{number}/merge"
45
47
 
46
48
  @api_interface.send_request(api_path, http_method: :put)
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'time'
@@ -5,10 +6,13 @@ require 'time'
5
6
  module Geet
6
7
  module Helpers
7
8
  module JsonHelper
9
+ extend T::Sig
10
+
8
11
  # Most common Json time format.
9
12
  #
10
13
  # Returns nil if nil is passed.
11
14
  #
15
+ sig { params(timestamp: T.nilable(String)).returns(T.nilable(Date)) }
12
16
  def parse_iso_8601_timestamp(timestamp)
13
17
  Time.iso8601(timestamp).to_date if timestamp
14
18
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # typed: true
2
3
 
3
4
  require 'English'
4
5
  require 'open3'
@@ -7,6 +8,11 @@ require 'shellwords'
7
8
  module Geet
8
9
  module Helpers
9
10
  module OsHelper
11
+ extend T::Sig
12
+
13
+ include Kernel # for Sorbet compatibility
14
+
15
+ sig { params(file_or_url: String).void }
10
16
  def open_file_with_default_application(file_or_url)
11
17
  open_command = case
12
18
  when ENV["WSL_DISTRO_NAME"]
@@ -29,12 +35,16 @@ module Geet
29
35
  # On non-interactive runs, the stdout content is returned, stripped of the surrounding
30
36
  # whitespaces.
31
37
  #
32
- # description: optional string, to make the error clearer.
33
- # interactive: set when required; in this case, a different API will be used (`system()`
34
- # instead of `popen3`).
35
- # silent_stderr: don't print the stderr output
36
- # allow_error: don't raise error on failure
37
- #
38
+ sig {
39
+ params(
40
+ command: String,
41
+ description: T.nilable(String), # specify to make the error clearer
42
+ interactive: T::Boolean, # set when required; in this case, a different API will be used (`system()`
43
+ # instead of `popen3`)
44
+ silent_stderr: T::Boolean, # don't print the stderr output
45
+ allow_error: T::Boolean # don't raise error on failure
46
+ ).returns(T.nilable(String))
47
+ }
38
48
  def execute_command(command, description: nil, interactive: false, silent_stderr: false, allow_error: false)
39
49
  description_message = " on #{description}" if description
40
50
 
@@ -45,6 +55,8 @@ module Geet
45
55
  raise "Error#{description_message} (exit status: #{$CHILD_STATUS.exitstatus})"
46
56
  end
47
57
  else
58
+ result = ""
59
+
48
60
  Open3.popen3(command) do |_, stdout, stderr, wait_thread|
49
61
  stdout_content = stdout.read
50
62
  stderr_content = stderr.read
@@ -56,8 +68,10 @@ module Geet
56
68
  raise "Error#{description_message}: #{error_message}"
57
69
  end
58
70
 
59
- stdout_content.strip
71
+ result = stdout_content.strip
60
72
  end
73
+
74
+ result
61
75
  end
62
76
  end
63
77
  end
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'English'
@@ -9,10 +10,21 @@ module Geet
9
10
  # Helper for services common workflow, for example, find the merge head.
10
11
  #
11
12
  module ServicesWorkflowHelper
13
+ include Kernel
14
+ extend T::Sig
15
+
16
+ sig { void }
17
+ def initialize
18
+ @repository = T.let(T.unsafe(nil), Git::Repository)
19
+ @git_client = T.let(T.unsafe(nil), Utils::GitClient)
20
+ @out = T.let(T.unsafe(nil), IO)
21
+ end
22
+
12
23
  # Expect to find only one.
13
24
  #
14
25
  # Requires: @out, @repository.
15
26
  #
27
+ sig { returns(T.any(Geet::Github::PR, Geet::Gitlab::PR)) }
16
28
  def checked_find_branch_pr
17
29
  owner = if @repository.upstream?
18
30
  @repository.authenticated_user.username
@@ -1,16 +1,23 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  module Geet
4
5
  module Helpers
5
6
  module SummaryHelper
7
+ include Kernel
8
+ extend T::Sig
9
+
6
10
  # Split the summary in title and description.
7
11
  # The description is optional, but the title mandatory.
8
12
  #
13
+ sig { params(summary: String).returns([String, String]) }
9
14
  def split_summary(summary)
10
15
  raise "Missing title in summary!" if summary.to_s.strip.empty?
11
16
 
12
17
  title, description = summary.split(/\r|\n/, 2)
13
18
 
19
+ raise "Title missing" if title.nil?
20
+
14
21
  # The title may have a residual newline char; the description may not be present,
15
22
  # or have multiple blank lines.
16
23
  [title.strip, description.to_s.strip]
@@ -1,17 +1,17 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
4
+ require 'stringio'
3
5
  require 'tmpdir'
4
6
 
5
- require_relative '../helpers/os_helper'
6
- require_relative '../utils/attributes_selection_manager'
7
- require_relative '../utils/manual_list_selection'
8
- require_relative '../utils/string_matching_selection'
9
-
10
7
  module Geet
11
8
  module Services
12
9
  class AbstractCreateIssue
10
+ extend T::Sig
11
+
13
12
  include Geet::Helpers::OsHelper
14
13
 
14
+ sig { params(repository: T.untyped, out: T.any(IO, StringIO)).void }
15
15
  def initialize(repository, out: $stdout)
16
16
  @repository = repository
17
17
  @out = out
@@ -1,18 +1,23 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
4
  module Geet
4
5
  module Services
5
6
  # Add the upstream repository to the current repository (configuration).
6
7
  #
7
8
  class AddUpstreamRepo
9
+ extend T::Sig
10
+
8
11
  DEFAULT_GIT_CLIENT = Utils::GitClient.new
9
12
 
13
+ sig { params(repository: T.untyped, out: T.any(IO, StringIO), git_client: T.untyped).void }
10
14
  def initialize(repository, out: $stdout, git_client: DEFAULT_GIT_CLIENT)
11
15
  @repository = repository
12
16
  @out = out
13
17
  @git_client = git_client
14
18
  end
15
19
 
20
+ sig { void }
16
21
  def execute
17
22
  raise "Upstream remote already existing!" if @git_client.remote_defined?(Utils::GitClient::UPSTREAM_NAME)
18
23
 
@@ -31,6 +36,7 @@ module Geet
31
36
 
32
37
  # Use the same protocol as the main repository.
33
38
  #
39
+ sig { params(parent_path: String).returns((String)) }
34
40
  def compose_parent_url(parent_path)
35
41
  protocol, domain, separator, _, suffix = @git_client.remote_components
36
42
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../shared/selection'
4
-
5
3
  module Geet
6
4
  module Services
7
5
  class CloseMilestones
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../helpers/os_helper'
4
- require_relative '../helpers/services_workflow_helper'
5
-
6
3
  module Geet
7
4
  module Services
8
5
  # Add a comment to the PR for the current branch.
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../helpers/os_helper'
4
- require_relative '../github/api_interface'
5
- require_relative '../github/gist'
6
-
7
3
  module Geet
8
4
  module Services
9
5
  class CreateGist
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'abstract_create_issue'
4
- require_relative '../shared/repo_permissions'
5
- require_relative '../shared/selection'
6
-
7
3
  module Geet
8
4
  module Services
9
5
  class CreateIssue < AbstractCreateIssue