geet 0.27.1 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +79 -58
- data/Gemfile +9 -9
- data/Rakefile +2 -2
- data/bin/geet +7 -7
- data/geet.gemspec +19 -19
- data/lib/geet/commandline/commands.rb +16 -15
- data/lib/geet/commandline/configuration.rb +97 -93
- data/lib/geet/commandline/editor.rb +13 -7
- data/lib/geet/git/repository.rb +75 -6
- data/lib/geet/github/abstract_issue.rb +7 -7
- data/lib/geet/github/api_interface.rb +23 -23
- data/lib/geet/github/gist.rb +8 -8
- data/lib/geet/github/issue.rb +6 -6
- data/lib/geet/github/label.rb +5 -5
- data/lib/geet/github/milestone.rb +10 -10
- data/lib/geet/github/pr.rb +25 -25
- data/lib/geet/github/remote_repository.rb +1 -1
- data/lib/geet/github/user.rb +5 -5
- data/lib/geet/gitlab/api_interface.rb +13 -13
- data/lib/geet/gitlab/issue.rb +3 -3
- data/lib/geet/gitlab/label.rb +4 -4
- data/lib/geet/gitlab/milestone.rb +4 -4
- data/lib/geet/gitlab/pr.rb +4 -4
- data/lib/geet/gitlab/user.rb +2 -2
- data/lib/geet/helpers/json_helper.rb +1 -1
- data/lib/geet/helpers/os_helper.rb +5 -5
- data/lib/geet/helpers/services_workflow_helper.rb +4 -4
- data/lib/geet/services/abstract_create_issue.rb +3 -3
- data/lib/geet/services/add_upstream_repo.rb +1 -1
- data/lib/geet/services/close_milestones.rb +9 -2
- data/lib/geet/services/comment_pr.rb +11 -0
- data/lib/geet/services/create_gist.rb +18 -4
- data/lib/geet/services/create_issue.rb +14 -8
- data/lib/geet/services/create_label.rb +22 -3
- data/lib/geet/services/create_milestone.rb +7 -1
- data/lib/geet/services/create_pr.rb +98 -23
- data/lib/geet/services/list_issues.rb +4 -3
- data/lib/geet/services/list_labels.rb +7 -0
- data/lib/geet/services/list_milestones.rb +35 -6
- data/lib/geet/services/list_prs.rb +7 -0
- data/lib/geet/services/merge_pr.rb +20 -2
- data/lib/geet/services/open_pr.rb +2 -2
- data/lib/geet/services/open_repo.rb +7 -1
- data/lib/geet/shared/repo_permissions.rb +4 -4
- data/lib/geet/shared/selection.rb +2 -2
- data/lib/geet/utils/attributes_selection_manager.rb +30 -10
- data/lib/geet/utils/git_client.rb +74 -33
- data/lib/geet/utils/manual_list_selection.rb +23 -11
- data/lib/geet/utils/string_matching_selection.rb +22 -6
- data/lib/geet/version.rb +2 -1
- data/lib/geet.rb +2 -2
- data/spec/integration/comment_pr_spec.rb +10 -10
- data/spec/integration/create_gist_spec.rb +12 -12
- data/spec/integration/create_issue_spec.rb +21 -21
- data/spec/integration/create_label_spec.rb +33 -33
- data/spec/integration/create_milestone_spec.rb +9 -9
- data/spec/integration/create_pr_spec.rb +120 -134
- data/spec/integration/list_issues_spec.rb +25 -25
- data/spec/integration/list_labels_spec.rb +15 -15
- data/spec/integration/list_milestones_spec.rb +15 -15
- data/spec/integration/list_prs_spec.rb +10 -10
- data/spec/integration/merge_pr_spec.rb +18 -18
- data/spec/integration/open_pr_spec.rb +18 -20
- data/spec/integration/open_repo_spec.rb +18 -18
- data/spec/spec_helper.rb +10 -10
- data/spec/unit/github/pr_spec.rb +91 -91
- metadata +2 -3
- data/.rubocop_todo.yml +0 -466
|
@@ -1,28 +1,32 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: strict
|
|
2
3
|
|
|
3
|
-
require
|
|
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 =
|
|
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
|
-
|
|
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([
|
|
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:
|
|
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[
|
|
58
|
+
ENV["EDITOR"] || ENV["VISUAL"] || "vi"
|
|
53
59
|
end
|
|
54
60
|
end
|
|
55
61
|
end
|
data/lib/geet/git/repository.rb
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: strict
|
|
2
3
|
|
|
3
4
|
module Geet
|
|
4
5
|
module Git
|
|
5
6
|
# This class represents, for convenience, both the local and the remote repository, but the
|
|
6
7
|
# remote code is separated in each provider module.
|
|
7
8
|
class Repository
|
|
9
|
+
extend T::Sig
|
|
10
|
+
|
|
8
11
|
LOCAL_ACTION_ON_UPSTREAM_REPOSITORY_MESSAGE = <<~STR
|
|
9
12
|
The action will be performed on a fork, but an upstream repository has been found!
|
|
10
13
|
STR
|
|
@@ -15,28 +18,42 @@ module Geet
|
|
|
15
18
|
|
|
16
19
|
DEFAULT_GIT_CLIENT = Geet::Utils::GitClient.new
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
sig {
|
|
22
|
+
params(
|
|
23
|
+
upstream: T::Boolean,
|
|
24
|
+
git_client: Utils::GitClient,
|
|
25
|
+
warnings: T::Boolean, # disable all the warnings
|
|
26
|
+
protected_repositories: T::Array[String] # warn when creating an issue/pr on these repos (format: `owner/repo`)
|
|
27
|
+
)
|
|
28
|
+
.void
|
|
29
|
+
}
|
|
22
30
|
def initialize(upstream: false, git_client: DEFAULT_GIT_CLIENT, warnings: true, protected_repositories: [])
|
|
23
31
|
@upstream = upstream
|
|
24
32
|
@git_client = git_client
|
|
25
|
-
@api_token = extract_env_api_token
|
|
33
|
+
@api_token = T.let(extract_env_api_token, String)
|
|
26
34
|
@warnings = warnings
|
|
27
35
|
@protected_repositories = protected_repositories
|
|
28
36
|
end
|
|
29
37
|
|
|
30
38
|
# REMOTE FUNCTIONALITIES (REPOSITORY)
|
|
31
39
|
|
|
40
|
+
sig { returns(T.any(T::Array[Github::User], T::Array[Gitlab::User])) }
|
|
32
41
|
def collaborators
|
|
33
42
|
attempt_provider_call(:User, :list_collaborators, api_interface)
|
|
34
43
|
end
|
|
35
44
|
|
|
45
|
+
sig { returns(T.any(T::Array[Github::Label], T::Array[Gitlab::Label])) }
|
|
36
46
|
def labels
|
|
37
47
|
attempt_provider_call(:Label, :list, api_interface)
|
|
38
48
|
end
|
|
39
49
|
|
|
50
|
+
sig {
|
|
51
|
+
params(
|
|
52
|
+
title: String,
|
|
53
|
+
description: String
|
|
54
|
+
)
|
|
55
|
+
.returns(T.any(Github::Issue, Gitlab::Issue))
|
|
56
|
+
}
|
|
40
57
|
def create_issue(title, description)
|
|
41
58
|
confirm(LOCAL_ACTION_ON_UPSTREAM_REPOSITORY_MESSAGE) if local_action_on_upstream_repository? && @warnings
|
|
42
59
|
confirm(ACTION_ON_PROTECTED_REPOSITORY_MESSAGE) if action_on_protected_repository? && @warnings
|
|
@@ -44,30 +61,63 @@ module Geet
|
|
|
44
61
|
attempt_provider_call(:Issue, :create, title, description, api_interface)
|
|
45
62
|
end
|
|
46
63
|
|
|
64
|
+
sig {
|
|
65
|
+
params(
|
|
66
|
+
name: String,
|
|
67
|
+
color: String
|
|
68
|
+
)
|
|
69
|
+
.returns(T.any(Github::Label, Gitlab::Label))
|
|
70
|
+
}
|
|
47
71
|
def create_label(name, color)
|
|
48
72
|
attempt_provider_call(:Label, :create, name, color, api_interface)
|
|
49
73
|
end
|
|
50
74
|
|
|
75
|
+
sig { params(name: String).void }
|
|
51
76
|
def delete_branch(name)
|
|
52
77
|
attempt_provider_call(:Branch, :delete, name, api_interface)
|
|
53
78
|
end
|
|
54
79
|
|
|
80
|
+
sig {
|
|
81
|
+
params(
|
|
82
|
+
assignee: T.nilable(T.any(Github::User, Gitlab::User)),
|
|
83
|
+
milestone: T.nilable(T.any(Github::Milestone, Gitlab::Milestone))
|
|
84
|
+
)
|
|
85
|
+
.returns(T.any(T::Array[Github::AbstractIssue], T::Array[Gitlab::Issue]))
|
|
86
|
+
}
|
|
55
87
|
def issues(assignee: nil, milestone: nil)
|
|
56
88
|
attempt_provider_call(:Issue, :list, api_interface, assignee:, milestone:)
|
|
57
89
|
end
|
|
58
90
|
|
|
91
|
+
sig {
|
|
92
|
+
params(
|
|
93
|
+
title: String
|
|
94
|
+
)
|
|
95
|
+
.returns(T.any(Github::Milestone, Gitlab::Milestone))
|
|
96
|
+
}
|
|
59
97
|
def create_milestone(title)
|
|
60
98
|
attempt_provider_call(:Milestone, :create, title, api_interface)
|
|
61
99
|
end
|
|
62
100
|
|
|
101
|
+
sig { returns(T.any(T::Array[Github::Milestone], T::Array[Gitlab::Milestone])) }
|
|
63
102
|
def milestones
|
|
64
103
|
attempt_provider_call(:Milestone, :list, api_interface)
|
|
65
104
|
end
|
|
66
105
|
|
|
106
|
+
sig { params(number: Integer).void }
|
|
67
107
|
def close_milestone(number)
|
|
68
108
|
attempt_provider_call(:Milestone, :close, number, api_interface)
|
|
69
109
|
end
|
|
70
110
|
|
|
111
|
+
sig {
|
|
112
|
+
params(
|
|
113
|
+
title: String,
|
|
114
|
+
description: String,
|
|
115
|
+
head: String, # source branch
|
|
116
|
+
base: String, # target branch
|
|
117
|
+
draft: T::Boolean
|
|
118
|
+
)
|
|
119
|
+
.returns(T.any(Github::PR, Gitlab::PR))
|
|
120
|
+
}
|
|
71
121
|
def create_pr(title, description, head, base, draft)
|
|
72
122
|
confirm(LOCAL_ACTION_ON_UPSTREAM_REPOSITORY_MESSAGE) if local_action_on_upstream_repository? && @warnings
|
|
73
123
|
confirm(ACTION_ON_PROTECTED_REPOSITORY_MESSAGE) if action_on_protected_repository? && @warnings
|
|
@@ -75,30 +125,42 @@ module Geet
|
|
|
75
125
|
attempt_provider_call(:PR, :create, title, description, head, api_interface, base, draft: draft)
|
|
76
126
|
end
|
|
77
127
|
|
|
128
|
+
sig {
|
|
129
|
+
params(
|
|
130
|
+
owner: T.nilable(String), # filter by repository owner
|
|
131
|
+
head: T.nilable(String), # filter by source branch
|
|
132
|
+
milestone: T.nilable(T.any(Github::Milestone, Gitlab::Milestone))
|
|
133
|
+
)
|
|
134
|
+
.returns(T.any(T::Array[Github::PR], T::Array[Gitlab::PR]))
|
|
135
|
+
}
|
|
78
136
|
def prs(owner: nil, head: nil, milestone: nil)
|
|
79
137
|
attempt_provider_call(:PR, :list, api_interface, owner:, head:, milestone:)
|
|
80
138
|
end
|
|
81
139
|
|
|
82
140
|
# Returns the RemoteRepository instance.
|
|
83
141
|
#
|
|
142
|
+
sig { returns(Github::RemoteRepository) }
|
|
84
143
|
def remote
|
|
85
144
|
attempt_provider_call(:RemoteRepository, :find, api_interface)
|
|
86
145
|
end
|
|
87
146
|
|
|
88
147
|
# REMOTE FUNCTIONALITIES (ACCOUNT)
|
|
89
148
|
|
|
149
|
+
sig { returns(Github::User) }
|
|
90
150
|
def authenticated_user
|
|
91
151
|
attempt_provider_call(:User, :authenticated, api_interface)
|
|
92
152
|
end
|
|
93
153
|
|
|
94
154
|
# OTHER/CONVENIENCE FUNCTIONALITIES
|
|
95
155
|
|
|
156
|
+
sig { returns(T::Boolean) }
|
|
96
157
|
def upstream?
|
|
97
158
|
@upstream
|
|
98
159
|
end
|
|
99
160
|
|
|
100
161
|
# For cases where it's necessary to work on the downstream repo.
|
|
101
162
|
#
|
|
163
|
+
sig { returns(Git::Repository) }
|
|
102
164
|
def downstream
|
|
103
165
|
raise "downstream() is not available on not-upstream repositories!" if !upstream?
|
|
104
166
|
|
|
@@ -109,6 +171,7 @@ module Geet
|
|
|
109
171
|
|
|
110
172
|
# PROVIDER
|
|
111
173
|
|
|
174
|
+
sig { returns(String) }
|
|
112
175
|
def extract_env_api_token
|
|
113
176
|
env_variable_name = "#{provider_name.upcase}_API_TOKEN"
|
|
114
177
|
|
|
@@ -117,6 +180,7 @@ module Geet
|
|
|
117
180
|
|
|
118
181
|
# Attempt to find the provider class and send the specified method, returning a friendly
|
|
119
182
|
# error (functionality X [Y] is missing) when a class/method is missing.
|
|
183
|
+
sig { params(class_name: Symbol, meth: Symbol, args: T.untyped).returns(T.untyped) }
|
|
120
184
|
def attempt_provider_call(class_name, meth, *args)
|
|
121
185
|
module_name = provider_name.capitalize
|
|
122
186
|
|
|
@@ -142,23 +206,27 @@ module Geet
|
|
|
142
206
|
|
|
143
207
|
# WARNINGS
|
|
144
208
|
|
|
209
|
+
sig { params(message: String).void }
|
|
145
210
|
def confirm(message)
|
|
146
211
|
full_message = "WARNING! #{message.strip}\nPress Enter to continue, or Ctrl+C to exit now."
|
|
147
212
|
print full_message
|
|
148
213
|
gets
|
|
149
214
|
end
|
|
150
215
|
|
|
216
|
+
sig { returns(T::Boolean) }
|
|
151
217
|
def action_on_protected_repository?
|
|
152
218
|
path = @git_client.path(upstream: @upstream)
|
|
153
219
|
@protected_repositories.include?(path)
|
|
154
220
|
end
|
|
155
221
|
|
|
222
|
+
sig { returns(T::Boolean) }
|
|
156
223
|
def local_action_on_upstream_repository?
|
|
157
224
|
@git_client.remote_defined?(Utils::GitClient::UPSTREAM_NAME) && !@upstream
|
|
158
225
|
end
|
|
159
226
|
|
|
160
227
|
# OTHER HELPERS
|
|
161
228
|
|
|
229
|
+
sig { returns(T.any(Github::ApiInterface, Gitlab::ApiInterface)) }
|
|
162
230
|
def api_interface
|
|
163
231
|
path = @git_client.path(upstream: @upstream)
|
|
164
232
|
attempt_provider_call(:ApiInterface, :new, @api_token, repo_path: path, upstream: @upstream)
|
|
@@ -166,8 +234,9 @@ module Geet
|
|
|
166
234
|
|
|
167
235
|
# Bare downcase provider name, eg. `github`
|
|
168
236
|
#
|
|
237
|
+
sig { returns(String) }
|
|
169
238
|
def provider_name
|
|
170
|
-
@git_client.provider_domain[/(.*)\.\w+/, 1]
|
|
239
|
+
T.must(@git_client.provider_domain[/(.*)\.\w+/, 1])
|
|
171
240
|
end
|
|
172
241
|
end
|
|
173
242
|
end
|
|
@@ -48,7 +48,7 @@ module Geet
|
|
|
48
48
|
)
|
|
49
49
|
).returns(T::Array[Geet::Github::AbstractIssue]) }
|
|
50
50
|
def self.list(api_interface, milestone: nil, assignee: nil, &type_filter)
|
|
51
|
-
api_path =
|
|
51
|
+
api_path = "issues"
|
|
52
52
|
|
|
53
53
|
request_params = {}
|
|
54
54
|
request_params[:milestone] = milestone.number if milestone
|
|
@@ -57,9 +57,9 @@ module Geet
|
|
|
57
57
|
response = T.cast(api_interface.send_request(api_path, params: request_params, multipage: true), T::Array[T::Hash[String, T.untyped]])
|
|
58
58
|
|
|
59
59
|
abstract_issues_list = response.map do |issue_data|
|
|
60
|
-
number = T.cast(issue_data.fetch(
|
|
61
|
-
title = T.cast(issue_data.fetch(
|
|
62
|
-
link = T.cast(issue_data.fetch(
|
|
60
|
+
number = T.cast(issue_data.fetch("number"), Integer)
|
|
61
|
+
title = T.cast(issue_data.fetch("title"), String)
|
|
62
|
+
link = T.cast(issue_data.fetch("html_url"), String)
|
|
63
63
|
|
|
64
64
|
new(number, api_interface, title, link) if type_filter.nil? || type_filter.call(issue_data)
|
|
65
65
|
end
|
|
@@ -70,7 +70,7 @@ module Geet
|
|
|
70
70
|
sig { params(users: T.any(String, T::Array[String])).void }
|
|
71
71
|
def assign_users(users)
|
|
72
72
|
api_path = "issues/#{@number}/assignees"
|
|
73
|
-
request_data = {
|
|
73
|
+
request_data = {assignees: Array(users)}
|
|
74
74
|
|
|
75
75
|
@api_interface.send_request(api_path, data: request_data)
|
|
76
76
|
end
|
|
@@ -87,7 +87,7 @@ module Geet
|
|
|
87
87
|
sig { params(comment: String).void }
|
|
88
88
|
def comment(comment)
|
|
89
89
|
api_path = "issues/#{@number}/comments"
|
|
90
|
-
request_data = {
|
|
90
|
+
request_data = {body: comment}
|
|
91
91
|
|
|
92
92
|
@api_interface.send_request(api_path, data: request_data)
|
|
93
93
|
end
|
|
@@ -96,7 +96,7 @@ module Geet
|
|
|
96
96
|
#
|
|
97
97
|
sig { params(milestone: Integer).void }
|
|
98
98
|
def edit(milestone:)
|
|
99
|
-
request_data = {
|
|
99
|
+
request_data = {milestone: milestone}
|
|
100
100
|
api_path = "issues/#{@number}"
|
|
101
101
|
|
|
102
102
|
@api_interface.send_request(api_path, data: request_data, http_method: :patch)
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# typed: strict
|
|
3
3
|
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
4
|
+
require "uri"
|
|
5
|
+
require "net/http"
|
|
6
|
+
require "json"
|
|
7
7
|
|
|
8
8
|
module Geet
|
|
9
9
|
module Github
|
|
10
10
|
class ApiInterface
|
|
11
11
|
extend T::Sig
|
|
12
12
|
|
|
13
|
-
API_AUTH_USER = T.let(
|
|
14
|
-
API_BASE_URL = T.let(
|
|
15
|
-
GRAPHQL_API_URL = T.let(
|
|
13
|
+
API_AUTH_USER = T.let("", String) # We don't need the login, as the API key uniquely identifies the user
|
|
14
|
+
API_BASE_URL = T.let("https://api.github.com", String)
|
|
15
|
+
GRAPHQL_API_URL = T.let("https://api.github.com/graphql", String)
|
|
16
16
|
|
|
17
17
|
sig { returns(T.nilable(String)) }
|
|
18
18
|
attr_reader :repository_path
|
|
@@ -111,7 +111,7 @@ module Geet
|
|
|
111
111
|
Net::HTTP.start(uri.host, use_ssl: true) do |http|
|
|
112
112
|
request = Net::HTTP::Post.new(uri).tap do
|
|
113
113
|
it.basic_auth API_AUTH_USER, @api_token
|
|
114
|
-
it[
|
|
114
|
+
it["Accept"] = "application/vnd.github.v3+json"
|
|
115
115
|
it.body = {query:, variables:}.to_json
|
|
116
116
|
end
|
|
117
117
|
|
|
@@ -127,12 +127,12 @@ module Geet
|
|
|
127
127
|
raise Geet::Shared::HttpError.new(error_message, response.code)
|
|
128
128
|
end
|
|
129
129
|
|
|
130
|
-
if parsed_response&.key?(
|
|
131
|
-
error_messages = T.cast(parsed_response[
|
|
130
|
+
if parsed_response&.key?("errors")
|
|
131
|
+
error_messages = T.cast(parsed_response["errors"], T::Array[T::Hash[String, T.untyped]]).map { |err| T.cast(err["message"], String) }.join(", ")
|
|
132
132
|
raise Geet::Shared::HttpError.new("GraphQL errors: #{error_messages}", response.code)
|
|
133
133
|
end
|
|
134
134
|
|
|
135
|
-
T.cast(T.must(parsed_response).fetch(
|
|
135
|
+
T.cast(T.must(parsed_response).fetch("data"), T::Hash[String, T.untyped])
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
138
|
|
|
@@ -146,8 +146,8 @@ module Geet
|
|
|
146
146
|
def api_url(api_path)
|
|
147
147
|
url = API_BASE_URL
|
|
148
148
|
|
|
149
|
-
if !api_path.start_with?(
|
|
150
|
-
raise
|
|
149
|
+
if !api_path.start_with?("/")
|
|
150
|
+
raise "Missing repo path!" if @repository_path.nil?
|
|
151
151
|
url += "/repos/#{@repository_path}/"
|
|
152
152
|
end
|
|
153
153
|
|
|
@@ -171,7 +171,7 @@ module Geet
|
|
|
171
171
|
|
|
172
172
|
request.basic_auth API_AUTH_USER, @api_token
|
|
173
173
|
request.body = data.to_json if data
|
|
174
|
-
request[
|
|
174
|
+
request["Accept"] = "application/vnd.github.v3+json"
|
|
175
175
|
|
|
176
176
|
http.request(request)
|
|
177
177
|
end
|
|
@@ -184,7 +184,7 @@ module Geet
|
|
|
184
184
|
).returns(URI::Generic)
|
|
185
185
|
}
|
|
186
186
|
def encode_uri(address, params)
|
|
187
|
-
address +=
|
|
187
|
+
address += "?" + URI.encode_www_form(params) if params
|
|
188
188
|
|
|
189
189
|
URI(address)
|
|
190
190
|
end
|
|
@@ -195,7 +195,7 @@ module Geet
|
|
|
195
195
|
).returns(T::Boolean)
|
|
196
196
|
}
|
|
197
197
|
def error?(response)
|
|
198
|
-
!response.code.start_with?(
|
|
198
|
+
!response.code.start_with?("2")
|
|
199
199
|
end
|
|
200
200
|
|
|
201
201
|
sig {
|
|
@@ -204,22 +204,22 @@ module Geet
|
|
|
204
204
|
).returns(String)
|
|
205
205
|
}
|
|
206
206
|
def decode_and_format_error(parsed_response)
|
|
207
|
-
message = parsed_response[
|
|
207
|
+
message = parsed_response["message"]
|
|
208
208
|
|
|
209
|
-
if parsed_response.key?(
|
|
210
|
-
message +=
|
|
209
|
+
if parsed_response.key?("errors")
|
|
210
|
+
message += ":"
|
|
211
211
|
|
|
212
|
-
error_details = parsed_response[
|
|
213
|
-
error_code = error_data.fetch(
|
|
212
|
+
error_details = parsed_response["errors"].map do |error_data|
|
|
213
|
+
error_code = error_data.fetch("code")
|
|
214
214
|
|
|
215
|
-
if error_code ==
|
|
215
|
+
if error_code == "custom"
|
|
216
216
|
" #{error_data.fetch('message')}"
|
|
217
217
|
else
|
|
218
218
|
" #{error_code} (#{error_data.fetch('field')})"
|
|
219
219
|
end
|
|
220
220
|
end
|
|
221
221
|
|
|
222
|
-
message += error_details.join(
|
|
222
|
+
message += error_details.join(", ")
|
|
223
223
|
end
|
|
224
224
|
|
|
225
225
|
message
|
|
@@ -232,7 +232,7 @@ module Geet
|
|
|
232
232
|
}
|
|
233
233
|
def link_next_page(response_headers)
|
|
234
234
|
# An array (or nil) is returned.
|
|
235
|
-
link_header = Array(response_headers[
|
|
235
|
+
link_header = Array(response_headers["link"])
|
|
236
236
|
|
|
237
237
|
return nil if link_header.empty?
|
|
238
238
|
|
data/lib/geet/github/gist.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# typed: strict
|
|
3
3
|
|
|
4
|
-
require_relative
|
|
5
|
-
require_relative
|
|
4
|
+
require_relative "abstract_issue"
|
|
5
|
+
require_relative "../github/gist"
|
|
6
6
|
|
|
7
7
|
module Geet
|
|
8
8
|
module Github
|
|
@@ -19,13 +19,13 @@ module Geet
|
|
|
19
19
|
).returns(Geet::Github::Gist)
|
|
20
20
|
}
|
|
21
21
|
def self.create(filename, content, api_interface, description: nil, publik: false)
|
|
22
|
-
api_path =
|
|
22
|
+
api_path = "/gists"
|
|
23
23
|
|
|
24
24
|
request_data = prepare_request_data(filename, content, description, publik)
|
|
25
25
|
|
|
26
26
|
response = T.cast(api_interface.send_request(api_path, data: T.unsafe(request_data)), T::Hash[String, T.untyped])
|
|
27
27
|
|
|
28
|
-
id = T.cast(response.fetch(
|
|
28
|
+
id = T.cast(response.fetch("id"), String)
|
|
29
29
|
|
|
30
30
|
new(id)
|
|
31
31
|
end
|
|
@@ -55,15 +55,15 @@ module Geet
|
|
|
55
55
|
}
|
|
56
56
|
def prepare_request_data(filename, content, description, publik)
|
|
57
57
|
request_data = {
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
"public" => publik,
|
|
59
|
+
"files" => {
|
|
60
60
|
filename => {
|
|
61
|
-
|
|
61
|
+
"content" => content,
|
|
62
62
|
},
|
|
63
63
|
},
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
request_data[
|
|
66
|
+
request_data["description"] = description if description
|
|
67
67
|
|
|
68
68
|
request_data
|
|
69
69
|
end
|
data/lib/geet/github/issue.rb
CHANGED
|
@@ -14,17 +14,17 @@ module Geet
|
|
|
14
14
|
).returns(Geet::Github::Issue)
|
|
15
15
|
}
|
|
16
16
|
def self.create(title, description, api_interface)
|
|
17
|
-
api_path =
|
|
18
|
-
request_data = {
|
|
17
|
+
api_path = "issues"
|
|
18
|
+
request_data = {title:, body: description}
|
|
19
19
|
|
|
20
20
|
response = T.cast(
|
|
21
21
|
api_interface.send_request(api_path, data: request_data),
|
|
22
22
|
T::Hash[String, T.untyped]
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
issue_number = T.cast(response.fetch(
|
|
26
|
-
title = T.cast(response.fetch(
|
|
27
|
-
link = T.cast(response.fetch(
|
|
25
|
+
issue_number = T.cast(response.fetch("number"), Integer)
|
|
26
|
+
title = T.cast(response.fetch("title"), String)
|
|
27
|
+
link = T.cast(response.fetch("html_url"), String)
|
|
28
28
|
|
|
29
29
|
new(issue_number, api_interface, title, link)
|
|
30
30
|
end
|
|
@@ -42,7 +42,7 @@ module Geet
|
|
|
42
42
|
}
|
|
43
43
|
def self.list(api_interface, assignee: nil, milestone: nil, &type_filter)
|
|
44
44
|
super do |issue_data|
|
|
45
|
-
!issue_data.key?(
|
|
45
|
+
!issue_data.key?("pull_request")
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
end
|
data/lib/geet/github/label.rb
CHANGED
|
@@ -29,12 +29,12 @@ module Geet
|
|
|
29
29
|
).returns(T::Array[Geet::Github::Label])
|
|
30
30
|
}
|
|
31
31
|
def self.list(api_interface)
|
|
32
|
-
api_path =
|
|
32
|
+
api_path = "labels"
|
|
33
33
|
response = T.cast(api_interface.send_request(api_path, multipage: true), T::Array[T::Hash[String, T.untyped]])
|
|
34
34
|
|
|
35
35
|
response.map do |label_entry|
|
|
36
|
-
name = T.cast(label_entry.fetch(
|
|
37
|
-
color = T.cast(label_entry.fetch(
|
|
36
|
+
name = T.cast(label_entry.fetch("name"), String)
|
|
37
|
+
color = T.cast(label_entry.fetch("color"), String)
|
|
38
38
|
|
|
39
39
|
new(name, color)
|
|
40
40
|
end
|
|
@@ -49,8 +49,8 @@ module Geet
|
|
|
49
49
|
).returns(Geet::Github::Label)
|
|
50
50
|
}
|
|
51
51
|
def self.create(name, color, api_interface)
|
|
52
|
-
api_path =
|
|
53
|
-
request_data = {
|
|
52
|
+
api_path = "labels"
|
|
53
|
+
request_data = {name:, color:}
|
|
54
54
|
|
|
55
55
|
api_interface.send_request(api_path, data: request_data)
|
|
56
56
|
|
|
@@ -15,7 +15,7 @@ module Geet
|
|
|
15
15
|
sig { returns(T.nilable(Date)) }
|
|
16
16
|
attr_reader :due_on
|
|
17
17
|
|
|
18
|
-
STATE_CLOSED =
|
|
18
|
+
STATE_CLOSED = "closed"
|
|
19
19
|
|
|
20
20
|
class << self
|
|
21
21
|
extend T::Sig
|
|
@@ -49,16 +49,16 @@ module Geet
|
|
|
49
49
|
).returns(Geet::Github::Milestone)
|
|
50
50
|
}
|
|
51
51
|
def self.create(title, api_interface)
|
|
52
|
-
api_path =
|
|
53
|
-
request_data = {
|
|
52
|
+
api_path = "milestones"
|
|
53
|
+
request_data = {title: title}
|
|
54
54
|
|
|
55
55
|
response = T.cast(
|
|
56
56
|
api_interface.send_request(api_path, data: request_data),
|
|
57
57
|
T::Hash[String, T.untyped]
|
|
58
58
|
)
|
|
59
59
|
|
|
60
|
-
number = T.cast(response.fetch(
|
|
61
|
-
title = T.cast(response.fetch(
|
|
60
|
+
number = T.cast(response.fetch("number"), Integer)
|
|
61
|
+
title = T.cast(response.fetch("title"), String)
|
|
62
62
|
due_on = nil
|
|
63
63
|
|
|
64
64
|
new(number, title, due_on, api_interface)
|
|
@@ -72,7 +72,7 @@ module Geet
|
|
|
72
72
|
).returns(T::Array[Geet::Github::Milestone])
|
|
73
73
|
}
|
|
74
74
|
def self.list(api_interface)
|
|
75
|
-
api_path =
|
|
75
|
+
api_path = "milestones"
|
|
76
76
|
|
|
77
77
|
response = T.cast(
|
|
78
78
|
api_interface.send_request(api_path, multipage: true),
|
|
@@ -80,10 +80,10 @@ module Geet
|
|
|
80
80
|
)
|
|
81
81
|
|
|
82
82
|
response.map do |milestone_data|
|
|
83
|
-
number = T.cast(milestone_data.fetch(
|
|
84
|
-
title = T.cast(milestone_data.fetch(
|
|
83
|
+
number = T.cast(milestone_data.fetch("number"), Integer)
|
|
84
|
+
title = T.cast(milestone_data.fetch("title"), String)
|
|
85
85
|
due_on = parse_iso_8601_timestamp(
|
|
86
|
-
T.cast(milestone_data.fetch(
|
|
86
|
+
T.cast(milestone_data.fetch("due_on"), T.nilable(String))
|
|
87
87
|
)
|
|
88
88
|
|
|
89
89
|
new(number, title, due_on, api_interface)
|
|
@@ -102,7 +102,7 @@ module Geet
|
|
|
102
102
|
}
|
|
103
103
|
def self.close(number, api_interface)
|
|
104
104
|
api_path = "milestones/#{number}"
|
|
105
|
-
request_data = {
|
|
105
|
+
request_data = {state: STATE_CLOSED}
|
|
106
106
|
|
|
107
107
|
api_interface.send_request(api_path, data: request_data)
|
|
108
108
|
end
|