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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c37242c53ca13fb80b44930526950f9bc17c94ee7a3075d535451c76a599f2e
4
- data.tar.gz: bf8b1009433f594a4da608d6e7a03b85e1954cb6afe82bc733fbad3c6e6ca300
3
+ metadata.gz: f2ac451d0da31fbee370de9c62f1b500895c606667a1dad15fed2fa29230a830
4
+ data.tar.gz: 032d99971b07e75417005cb096c2b0fb4e1b752866453fe708c422ada5778794
5
5
  SHA512:
6
- metadata.gz: 43681773afc1da211b90587d02f88ca6b8a8e4045398ccdb96b68e1e18f69eb9a2a3f484c075dcf1d5fb13c4f9a19a0e221df503b0546d34617ae2a9b273513d
7
- data.tar.gz: 8f139010b72eb1df6a32943909443ed5c54d1ff968236fbb040a85f276706776b6e8d23fadb906028aa910070364422b56ff93901e0908d1e0d271eaae3f07cc
6
+ metadata.gz: 9ccffdb2b7688650b4e4d16f8bf3cdf3c1503941fb3739356a249e6bf570b6cd737ba6393a30755e255df36c4454e6806beb64f67dd70312e6e6cc7edb115dbc
7
+ data.tar.gz: 9008e5a5f4a00cd750d97fb6bb76ca1f93d7372b0bfb1079294488a311ecfbb0cebda44ae0e690b75c13147c5d114e45f331fa3ff61b9405d7c8b5d0b5363abd
data/.rubocop.yml CHANGED
@@ -55,6 +55,13 @@ Layout/SpaceInsideStringInterpolation:
55
55
  Enabled: true
56
56
  EnforcedStyle: no_space
57
57
 
58
+ # Enforce double quotes for strings unless interpolation or escaping makes single quotes more convenient
59
+ # Examples: 'hello' -> "hello", 'foo #{bar}' -> "foo #{bar}", "foo \"bar\"" -> 'foo "bar"'
60
+ Style/StringLiterals:
61
+ Enabled: true
62
+ EnforcedStyle: double_quotes
63
+ ConsistentQuotesInMultiline: true
64
+
58
65
  # Ensure exactly one newline at the end of each file
59
66
  Layout/TrailingEmptyLines:
60
67
  Enabled: true
data/Gemfile CHANGED
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
7
  group :development do
8
- gem 'byebug'
9
- gem 'rubocop', '~> 1.82.1', require: false
10
- gem 'spoom', require: false
11
- gem 'tapioca', '>= 0.17.10', require: false
8
+ gem "byebug"
9
+ gem "rubocop", "~> 1.82.1", require: false
10
+ gem "spoom", require: false
11
+ gem "tapioca", ">= 0.17.10", require: false
12
12
  end
13
13
 
14
14
  group :test do
15
- gem 'rspec', '~> 3.13.0'
16
- gem 'rspec-sorbet'
17
- gem 'vcr', '~> 6.4.0'
18
- gem 'webmock', '~> 3.1.1'
15
+ gem "rspec", "~> 3.13.0"
16
+ gem "rspec-sorbet"
17
+ gem "vcr", "~> 6.4.0"
18
+ gem "webmock", "~> 3.1.1"
19
19
  end
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
- require 'rspec/core/rake_task'
1
+ require "rspec/core/rake_task"
2
2
 
3
3
  RSpec::Core::RakeTask.new(:spec) do |task|
4
- task.rspec_opts = ['--order rand']
4
+ task.rspec_opts = ["--order rand"]
5
5
  end
6
6
 
7
7
  task default: :spec
data/bin/geet CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'simple_scripting/configuration'
5
- require 'tmpdir'
6
- require_relative '../lib/geet'
4
+ require "simple_scripting/configuration"
5
+ require "tmpdir"
6
+ require_relative "../lib/geet"
7
7
 
8
8
  class GeetLauncher
9
9
  include Geet
10
10
  include Geet::Commandline::Commands
11
11
  include Geet::Helpers::SummaryHelper
12
12
 
13
- SUMMARY_TEMPLATE = IO.read(File.expand_path('../lib/geet/resources/templates/edit_summary.md', __dir__))
14
- SUMMARY_BACKUP = File.join(Dir.tmpdir, 'last_geet_edited_summary.md')
13
+ SUMMARY_TEMPLATE = IO.read(File.expand_path("../lib/geet/resources/templates/edit_summary.md", __dir__))
14
+ SUMMARY_BACKUP = File.join(Dir.tmpdir, "last_geet_edited_summary.md")
15
15
 
16
16
  def launch
17
17
  command, options = Commandline::Configuration.new.decode_argv || exit
@@ -98,7 +98,7 @@ class GeetLauncher
98
98
 
99
99
  Commandline::Editor.new.edit_content(content: prepopulated_summary, help: SUMMARY_TEMPLATE + cancel_pr_help)
100
100
  elsif pr_commits.size == 1
101
- prepopulated_summary = git.show_description('HEAD')
101
+ prepopulated_summary = git.show_description("HEAD")
102
102
 
103
103
  Commandline::Editor.new.edit_content(content: prepopulated_summary, help: SUMMARY_TEMPLATE + cancel_pr_help)
104
104
  else
@@ -121,7 +121,7 @@ class GeetLauncher
121
121
  def protected_repositories
122
122
  configuration = SimpleScripting::Configuration.load
123
123
 
124
- configuration.protected_repositories.to_s.split(':')
124
+ configuration.protected_repositories.to_s.split(":")
125
125
  end
126
126
  end
127
127
 
data/geet.gemspec CHANGED
@@ -1,30 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'lib/geet/version'
3
+ require_relative "lib/geet/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = 'geet'
6
+ s.name = "geet"
7
7
  s.version = Geet::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
- s.required_ruby_version = '>= 3.2.0'
10
- s.authors = ['Saverio Miroddi']
11
- s.date = '2026-01-18'
12
- s.email = ['saverio.pub2@gmail.com']
13
- s.homepage = 'https://github.com/saveriomiroddi/geet'
14
- s.summary = 'Commandline interface for performing SCM host operations, eg. create a PR on GitHub'
15
- s.description = 'Commandline interface for performing SCM host operations, eg. create a PR on GitHub, with support for multiple hosts.'
16
- s.license = 'GPL-3.0-only'
9
+ s.required_ruby_version = ">= 3.2.0"
10
+ s.authors = ["Saverio Miroddi"]
11
+ s.date = "2026-01-26"
12
+ s.email = ["saverio.pub2@gmail.com"]
13
+ s.homepage = "https://github.com/saveriomiroddi/geet"
14
+ s.summary = "Commandline interface for performing SCM host operations, eg. create a PR on GitHub"
15
+ s.description = "Commandline interface for performing SCM host operations, eg. create a PR on GitHub, with support for multiple hosts."
16
+ s.license = "GPL-3.0-only"
17
17
 
18
- s.add_runtime_dependency 'base64', '~> 0.3.0'
19
- s.add_runtime_dependency 'ostruct', '~> 0.6.3'
20
- s.add_runtime_dependency 'simple_scripting', '~> 0.14.0'
21
- s.add_runtime_dependency 'sorbet-runtime', '= 0.6.12883'
22
- s.add_runtime_dependency 'tty-prompt', '~> 0.23.1'
23
- s.add_runtime_dependency 'zeitwerk', '~> 2.7'
18
+ s.add_runtime_dependency "base64", "~> 0.3.0"
19
+ s.add_runtime_dependency "ostruct", "~> 0.6.3"
20
+ s.add_runtime_dependency "simple_scripting", "~> 0.14.0"
21
+ s.add_runtime_dependency "sorbet-runtime", "= 0.6.12883"
22
+ s.add_runtime_dependency "tty-prompt", "~> 0.23.1"
23
+ s.add_runtime_dependency "zeitwerk", "~> 2.7"
24
24
 
25
- s.add_development_dependency 'rake', '~> 12.3'
25
+ s.add_development_dependency "rake", "~> 12.3"
26
26
 
27
27
  s.files = `git ls-files`.split("\n")
28
- s.executables << 'geet'
29
- s.require_paths = ['lib']
28
+ s.executables << "geet"
29
+ s.require_paths = ["lib"]
30
30
  end
@@ -1,23 +1,24 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
4
  module Geet
4
5
  module Commandline
5
6
  module Commands
6
- GIST_CREATE_COMMAND = 'gist.create'
7
- ISSUE_CREATE_COMMAND = 'issue.create'
8
- LABEL_CREATE_COMMAND = 'label.create'
9
- ISSUE_LIST_COMMAND = 'issue.list'
10
- LABEL_LIST_COMMAND = 'label.list'
11
- MILESTONE_CLOSE_COMMAND = 'milestone.close'
12
- MILESTONE_CREATE_COMMAND = 'milestone.create'
13
- MILESTONE_LIST_COMMAND = 'milestone.list'
14
- PR_COMMENT_COMMAND = 'pr.comment'
15
- PR_CREATE_COMMAND = 'pr.create'
16
- PR_LIST_COMMAND = 'pr.list'
17
- PR_MERGE_COMMAND = 'pr.merge'
18
- PR_OPEN_COMMAND = 'pr.open'
19
- REPO_ADD_UPSTREAM_COMMAND = 'repo.add_upstream'
20
- REPO_OPEN_COMMAND = 'repo.open'
7
+ GIST_CREATE_COMMAND = T.let("gist.create", String)
8
+ ISSUE_CREATE_COMMAND = T.let("issue.create", String)
9
+ LABEL_CREATE_COMMAND = T.let("label.create", String)
10
+ ISSUE_LIST_COMMAND = T.let("issue.list", String)
11
+ LABEL_LIST_COMMAND = T.let("label.list", String)
12
+ MILESTONE_CLOSE_COMMAND = T.let("milestone.close", String)
13
+ MILESTONE_CREATE_COMMAND = T.let("milestone.create", String)
14
+ MILESTONE_LIST_COMMAND = T.let("milestone.list", String)
15
+ PR_COMMENT_COMMAND = T.let("pr.comment", String)
16
+ PR_CREATE_COMMAND = T.let("pr.create", String)
17
+ PR_LIST_COMMAND = T.let("pr.list", String)
18
+ PR_MERGE_COMMAND = T.let("pr.merge", String)
19
+ PR_OPEN_COMMAND = T.let("pr.open", String)
20
+ REPO_ADD_UPSTREAM_COMMAND = T.let("repo.add_upstream", String)
21
+ REPO_OPEN_COMMAND = T.let("repo.open", String)
21
22
  end
22
23
  end
23
24
  end
@@ -1,80 +1,83 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
- require 'simple_scripting/argv'
4
+ require "simple_scripting/argv"
4
5
 
5
6
  module Geet
6
7
  module Commandline
7
8
  class Configuration
9
+ extend T::Sig
10
+
8
11
  include Commands
9
12
 
10
13
  # Command options
11
14
 
12
15
  GIST_CREATE_OPTIONS = [
13
- ['-p', '--public'],
14
- ['-s', '--stdin', "Read content from stdin"],
15
- ['-o', '--open-browser', "Open the gist link in the browser after creation"],
16
- 'filename',
17
- '[description]',
16
+ ["-p", "--public"],
17
+ ["-s", "--stdin", "Read content from stdin"],
18
+ ["-o", "--open-browser", "Open the gist link in the browser after creation"],
19
+ "filename",
20
+ "[description]",
18
21
  ].freeze
19
22
 
20
23
  # SimpleScripting 0.9.3 doesn't allow frozen arrays when hash options are present.
21
24
  #
22
25
  # rubocop:disable Style/MutableConstant
23
- ISSUE_CREATE_OPTIONS = [
24
- ['-o', '--open-browser', "Don't open the issue link in the browser after creation"],
25
- ['-l', '--labels "bug,help wanted"', 'Labels'],
26
- ['-m', '--milestone 1.5.0', 'Milestone title pattern'],
27
- ['-a', '--assignees john,tom,adrian,kevin', 'Assignee logins'],
28
- ['-s', '--summary title_and_description', 'Set the summary (title and optionally description'],
29
- ['-u', '--upstream', 'Create on the upstream repository'],
30
- long_help: 'The default editor will be opened for editing title and description.',
31
- ]
26
+ ISSUE_CREATE_OPTIONS = T.let([
27
+ ["-o", "--open-browser", "Don't open the issue link in the browser after creation"],
28
+ ["-l", '--labels "bug,help wanted"', "Labels"],
29
+ ["-m", "--milestone 1.5.0", "Milestone title pattern"],
30
+ ["-a", "--assignees john,tom,adrian,kevin", "Assignee logins"],
31
+ ["-s", "--summary title_and_description", "Set the summary (title and optionally description"],
32
+ ["-u", "--upstream", "Create on the upstream repository"],
33
+ long_help: "The default editor will be opened for editing title and description.",
34
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], T::Array[String])])
32
35
 
33
36
  LABEL_CREATE_OPTIONS = [
34
- ['-c', '--color color', '6-digits hex color; if not specified, a random one is created'],
35
- ['-u', '--upstream', 'Create on the upstream repository'],
36
- 'name',
37
+ ["-c", "--color color", "6-digits hex color; if not specified, a random one is created"],
38
+ ["-u", "--upstream", "Create on the upstream repository"],
39
+ "name",
37
40
  ].freeze
38
41
 
39
42
  ISSUE_LIST_OPTIONS = [
40
- ['-a', '--assignee john', 'Assignee login'],
41
- ['-u', '--upstream', 'List on the upstream repository'],
43
+ ["-a", "--assignee john", "Assignee login"],
44
+ ["-u", "--upstream", "List on the upstream repository"],
42
45
  ].freeze
43
46
 
44
47
  LABEL_LIST_OPTIONS = [
45
- ['-u', '--upstream', 'List on the upstream repository'],
48
+ ["-u", "--upstream", "List on the upstream repository"],
46
49
  ].freeze
47
50
 
48
- MILESTONE_CLOSE_OPTIONS = [
49
- long_help: 'Close milestones.',
50
- ]
51
+ MILESTONE_CLOSE_OPTIONS = T.let([
52
+ long_help: "Close milestones.",
53
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], T::Array[String])])
51
54
 
52
- MILESTONE_CREATE_OPTIONS = [
53
- 'title',
54
- long_help: 'Create a milestone.',
55
- ]
55
+ MILESTONE_CREATE_OPTIONS = T.let([
56
+ "title",
57
+ long_help: "Create a milestone.",
58
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], String)])
56
59
 
57
60
  MILESTONE_LIST_OPTIONS = [
58
- ['-u', '--upstream', 'List on the upstream repository'],
61
+ ["-u", "--upstream", "List on the upstream repository"],
59
62
  ].freeze
60
63
 
61
- PR_COMMENT_OPTIONS = [
62
- ['-o', '--open-browser', "Don't open the PR link in the browser after creation"],
63
- ['-u', '--upstream', 'Comment on the upstream repository'],
64
- 'comment',
65
- long_help: 'Add a comment to the PR for the current branch.',
66
- ]
67
-
68
- PR_CREATE_OPTIONS = [
69
- ['-a', '--automerge', "Enable automerge (with default strategy)"],
70
- ['-o', '--open-browser', "Don't open the PR link in the browser after creation"],
71
- ['-b', '--base develop', "Specify the base branch; defaults to the main branch"],
72
- ['-d', '--draft', "Create as draft"],
73
- ['-l', '--labels "legacy,code review"', 'Labels'],
74
- ['-m', '--milestone 1.5.0', 'Milestone title pattern'],
75
- ['-r', '--reviewers john,tom,adrian,kevin', 'Reviewer logins'],
76
- ['-s', '--summary title_and_description', 'Set the summary (title and optionally description'],
77
- ['-u', '--upstream', 'Create on the upstream repository'],
64
+ PR_COMMENT_OPTIONS = T.let([
65
+ ["-o", "--open-browser", "Don't open the PR link in the browser after creation"],
66
+ ["-u", "--upstream", "Comment on the upstream repository"],
67
+ "comment",
68
+ long_help: "Add a comment to the PR for the current branch.",
69
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], T::Array[String], String)])
70
+
71
+ PR_CREATE_OPTIONS = T.let([
72
+ ["-a", "--automerge", "Enable automerge (with default strategy)"],
73
+ ["-o", "--open-browser", "Don't open the PR link in the browser after creation"],
74
+ ["-b", "--base develop", "Specify the base branch; defaults to the main branch"],
75
+ ["-d", "--draft", "Create as draft"],
76
+ ["-l", '--labels "legacy,code review"', "Labels"],
77
+ ["-m", "--milestone 1.5.0", "Milestone title pattern"],
78
+ ["-r", "--reviewers john,tom,adrian,kevin", "Reviewer logins"],
79
+ ["-s", "--summary title_and_description", "Set the summary (title and optionally description"],
80
+ ["-u", "--upstream", "Create on the upstream repository"],
78
81
  long_help: <<~STR,
79
82
  The default editor will be opened for editing title and description; if the PR adds one commit only, the content will be prepopulated with the commit description.
80
83
 
@@ -82,72 +85,73 @@ module Geet
82
85
 
83
86
  Before creating the PR, the local branch is pushed; if the remote branch is not present, it is created.
84
87
  STR
85
- ]
88
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], T::Array[String])])
86
89
 
87
90
  PR_LIST_OPTIONS = [
88
- ['-u', '--upstream', 'List on the upstream repository'],
91
+ ["-u", "--upstream", "List on the upstream repository"],
89
92
  ].freeze
90
93
 
91
94
  # SimpleScripting 0.9.3 doesn't allow frozen arrays when hash options are present.
92
95
  #
93
96
  # rubocop:disable Style/MutableConstant
94
- PR_MERGE_OPTIONS = [
95
- ['-d', '--delete-branch', 'Delete the branch after merging'],
96
- ['-s', '--squash', 'Squash merge'],
97
- ['-u', '--upstream', 'List on the upstream repository'],
98
- long_help: 'Merge the PR for the current branch',
99
- ]
100
-
101
- PR_OPEN_OPTIONS = [
102
- ['-u', '--upstream', 'Open on the upstream repository'],
103
- long_help: 'Open in the browser the PR for the current branch',
104
- ]
105
-
106
- REPO_ADD_UPSTREAM_OPTIONS = [
107
- long_help: 'Add the upstream repository to the current repository (configuration).',
108
- ]
109
-
110
- REPO_OPEN_OPTIONS = [
111
- ['-u', '--upstream', 'Open the upstream repository'],
112
- long_help: 'Open the current repository in the browser',
113
- ]
97
+ PR_MERGE_OPTIONS = T.let([
98
+ ["-d", "--delete-branch", "Delete the branch after merging"],
99
+ ["-s", "--squash", "Squash merge"],
100
+ ["-u", "--upstream", "List on the upstream repository"],
101
+ long_help: "Merge the PR for the current branch",
102
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], T::Array[String])])
103
+
104
+ PR_OPEN_OPTIONS = T.let([
105
+ ["-u", "--upstream", "Open on the upstream repository"],
106
+ long_help: "Open in the browser the PR for the current branch",
107
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], T::Array[String])])
108
+
109
+ REPO_ADD_UPSTREAM_OPTIONS = T.let([
110
+ long_help: "Add the upstream repository to the current repository (configuration).",
111
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], T::Array[String])])
112
+
113
+ REPO_OPEN_OPTIONS = T.let([
114
+ ["-u", "--upstream", "Open the upstream repository"],
115
+ long_help: "Open the current repository in the browser",
116
+ ], T::Array[T.any(T::Hash[T.untyped, T.untyped], T::Array[String])])
114
117
 
115
118
  # Commands decoding table
116
119
 
117
- COMMANDS_DECODING_TABLE = {
118
- 'gist' => {
119
- 'create' => GIST_CREATE_OPTIONS,
120
+ COMMANDS_DECODING_TABLE = T.let({
121
+ "gist" => {
122
+ "create" => GIST_CREATE_OPTIONS,
120
123
  },
121
- 'issue' => {
122
- 'create' => ISSUE_CREATE_OPTIONS,
123
- 'list' => ISSUE_LIST_OPTIONS,
124
+ "issue" => {
125
+ "create" => ISSUE_CREATE_OPTIONS,
126
+ "list" => ISSUE_LIST_OPTIONS,
124
127
  },
125
- 'label' => {
126
- 'create' => LABEL_CREATE_OPTIONS,
127
- 'list' => LABEL_LIST_OPTIONS,
128
+ "label" => {
129
+ "create" => LABEL_CREATE_OPTIONS,
130
+ "list" => LABEL_LIST_OPTIONS,
128
131
  },
129
- 'milestone' => {
130
- 'close' => MILESTONE_CLOSE_OPTIONS,
131
- 'create' => MILESTONE_CREATE_OPTIONS,
132
- 'list' => MILESTONE_LIST_OPTIONS,
132
+ "milestone" => {
133
+ "close" => MILESTONE_CLOSE_OPTIONS,
134
+ "create" => MILESTONE_CREATE_OPTIONS,
135
+ "list" => MILESTONE_LIST_OPTIONS,
133
136
  },
134
- 'pr' => {
135
- 'comment' => PR_COMMENT_OPTIONS,
136
- 'create' => PR_CREATE_OPTIONS,
137
- 'list' => PR_LIST_OPTIONS,
138
- 'merge' => PR_MERGE_OPTIONS,
139
- 'open' => PR_OPEN_OPTIONS,
137
+ "pr" => {
138
+ "comment" => PR_COMMENT_OPTIONS,
139
+ "create" => PR_CREATE_OPTIONS,
140
+ "list" => PR_LIST_OPTIONS,
141
+ "merge" => PR_MERGE_OPTIONS,
142
+ "open" => PR_OPEN_OPTIONS,
140
143
  },
141
- 'repo' => {
142
- 'add_upstream' => REPO_ADD_UPSTREAM_OPTIONS,
143
- 'open' => REPO_OPEN_OPTIONS,
144
+ "repo" => {
145
+ "add_upstream" => REPO_ADD_UPSTREAM_OPTIONS,
146
+ "open" => REPO_OPEN_OPTIONS,
144
147
  },
145
- }
148
+ }, T::Hash[T.untyped, T.untyped])
146
149
 
147
150
  # Public interface
148
151
 
152
+ sig { returns(T.nilable(T::Array[T.untyped])) }
149
153
  def decode_argv
150
- SimpleScripting::Argv.decode(COMMANDS_DECODING_TABLE)
154
+ T.unsafe(SimpleScripting::Argv).decode(COMMANDS_DECODING_TABLE)
151
155
  end
152
156
  end
153
157
  end
@@ -1,28 +1,32 @@
1
1
  # frozen_string_literal: true
2
+ # typed: strict
2
3
 
3
- require 'tempfile'
4
+ require "tempfile"
4
5
 
5
6
  module Geet
6
7
  module Commandline
7
8
  class Editor
9
+ extend T::Sig
10
+
8
11
  include Geet::Helpers::OsHelper
9
12
 
10
13
  # Git style!
11
- HELP_SEPARATOR = '------------------------ >8 ------------------------'
14
+ HELP_SEPARATOR = "------------------------ >8 ------------------------"
12
15
 
13
16
  # Edits a content in the default editor, optionally providing help.
14
17
  #
15
18
  # When the help is provided, it's appended to the bottom, separated by HELP_SEPARATOR.
16
19
  # The help is stripped after the content if edited.
17
20
  #
18
- def edit_content(content: '', help: nil)
21
+ sig { params(content: String, help: T.nilable(String)).returns(String) }
22
+ def edit_content(content: "", help: nil)
19
23
  content += "\n\n" + HELP_SEPARATOR + "\n" + help if help
20
24
 
21
25
  edited_content = edit_content_in_default_editor(content)
22
26
 
23
27
  edited_content = edited_content.split(HELP_SEPARATOR, 2).first if help
24
28
 
25
- edited_content.strip
29
+ T.must(edited_content).strip
26
30
  end
27
31
 
28
32
  private
@@ -33,11 +37,12 @@ module Geet
33
37
  # Interestingly, the API `TTY::Editor.open(content: 'text')` is not very useful,
34
38
  # as it doesn't return the filename (!).
35
39
  #
40
+ sig { params(content: String).returns(String) }
36
41
  def edit_content_in_default_editor(content)
37
- tempfile = Tempfile.open(['geet_editor', '.md']) { |file| file << content }.path
42
+ tempfile = T.must(Tempfile.open(["geet_editor", ".md"]) { |file| file << content }.path)
38
43
  command = "#{system_editor} #{tempfile.shellescape}"
39
44
 
40
- execute_command(command, description: 'editing', interactive: true)
45
+ execute_command(command, description: "editing", interactive: true)
41
46
 
42
47
  content = IO.read(tempfile)
43
48
 
@@ -48,8 +53,9 @@ module Geet
48
53
 
49
54
  # HELPERS ##########################################################################
50
55
 
56
+ sig { returns(String) }
51
57
  def system_editor
52
- ENV['EDITOR'] || ENV['VISUAL'] || 'vi'
58
+ ENV["EDITOR"] || ENV["VISUAL"] || "vi"
53
59
  end
54
60
  end
55
61
  end