Skip to content

Commit 6349685

Browse files
authored
fix(github_hooks): raise unknown error on unhandled octokit exception (#152)
When we receive an error from Octokit that we are not currently handling, the `pull_request` method on the repo host client returns nil, which can lead to a `undefined method `[]' for nil` error on the hook handler. See [this comment](renderedtext/tasks#7601 (comment)) for more details. Instead, to help us troubleshoot issues, we should log the actual error message that we are receiving from GitHub.
1 parent fcde29c commit 6349685

File tree

8 files changed

+95
-29
lines changed

8 files changed

+95
-29
lines changed

github_hooks/Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ GEM
246246
nio4r (~> 2.0)
247247
raabro (1.4.0)
248248
racc (1.8.1)
249-
rack (2.2.12)
249+
rack (2.2.13)
250250
rack-session (1.0.2)
251251
rack (< 3)
252252
rack-test (2.1.0)

github_hooks/lib/internal_api/repo_proxy/repo_proxy_server.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ class RepoProxyServer < RepoProxyService::Service
5151
end
5252
end
5353

54-
define_rpc :create do |req|
54+
define_rpc :create do |req, logger|
5555
project = ::Project.find(req.project_id)
5656

5757
if project.repository.integration_type.include?("github")
58-
create_for_github_project(req)
58+
create_for_github_project(req, logger)
5959
else
6060
create_via_hooks_api(req)
6161
end
@@ -66,7 +66,7 @@ def create_via_hooks_api(req)
6666
client.create(req)
6767
end
6868

69-
def create_for_github_project(req)
69+
def create_for_github_project(req, logger)
7070
project = ::Project.find(req.project_id)
7171
user = ::User.find(req.requester_id)
7272

@@ -155,6 +155,9 @@ def create_for_github_project(req)
155155
rescue ::RepoHost::RemoteException::NotFound
156156
workflow.update(:state => Workflow::STATE_NOT_FOUND_REPO)
157157
raise GRPC::NotFound, "Reference not found on GitHub #{req.git.reference} #{req.git.commit_sha}"
158+
rescue ::RepoHost::RemoteException::Unknown => e
159+
logger.error("Unknown error", error: e.message)
160+
raise GRPC::Unknown, "Unknown error"
158161
rescue ::ActiveRecord::RecordNotFound => e
159162
if e.model == User
160163
raise GRPC::NotFound, "Requester not found #{req.requester_id}"

github_hooks/lib/repo_host/github/client.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ def handle_octokit_exceptions(exception)
244244
raise ::RepoHost::RemoteException::MaximumNumberOfStatuses, exception.message
245245
elsif hook_exists?(exception)
246246
raise ::RepoHost::RemoteException::HookExistsOnRepository, exception.message
247+
else
248+
raise ::RepoHost::RemoteException::Unknown, exception.message
247249
end
248250
end
249251

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
class RepoHost::RemoteException::Unknown < RepoHost::RemoteException
2+
end

github_hooks/lib/semaphore/repo_host/hooks/handler.rb

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -179,31 +179,35 @@ def self.run(workflow, logger, hook_payload = "", signature = "", retries = 0)
179179
end
180180

181181
if workflow.payload.pull_request?
182-
state, meta, msg = update_pr_data(workflow.project, workflow.pull_request_number, workflow.commit_sha)
183-
184-
case state
185-
when :not_found
186-
logger.info("pr-not-found #{msg}")
187-
workflow.update(:state => Workflow::STATE_PR_NOT_FOUND)
188-
189-
return
190-
when :non_mergeable
191-
update_pull_request_mergeable(workflow, meta[:mergeable])
192-
193-
logger.info("pr-non-mergeable")
194-
workflow.update(:state => Workflow::STATE_PR_NON_MERGEABLE)
195-
196-
return
197-
when :skip_ci
198-
logger.info("request-is-filtered")
199-
workflow.update(:state => Workflow::STATE_SKIP_CI)
200-
201-
return
202-
when :without_reference
203-
logger.info("without-reference")
204-
workflow.update(:commit_author => meta[:commit_author])
205-
else
206-
workflow.update(:commit_author => meta[:commit_author], :commit_sha => meta[:merge_commit_sha], :git_ref => meta[:ref])
182+
begin
183+
state, meta, msg = update_pr_data(workflow.project, workflow.pull_request_number, workflow.commit_sha)
184+
case state
185+
when :not_found
186+
logger.info("pr-not-found #{msg}")
187+
workflow.update(:state => Workflow::STATE_PR_NOT_FOUND)
188+
189+
return
190+
when :non_mergeable
191+
update_pull_request_mergeable(workflow, meta[:mergeable])
192+
193+
logger.info("pr-non-mergeable")
194+
workflow.update(:state => Workflow::STATE_PR_NON_MERGEABLE)
195+
196+
return
197+
when :skip_ci
198+
logger.info("request-is-filtered")
199+
workflow.update(:state => Workflow::STATE_SKIP_CI)
200+
201+
return
202+
when :without_reference
203+
logger.info("without-reference")
204+
workflow.update(:commit_author => meta[:commit_author])
205+
else
206+
workflow.update(:commit_author => meta[:commit_author], :commit_sha => meta[:merge_commit_sha], :git_ref => meta[:ref])
207+
end
208+
rescue RepoHost::RemoteException::Unknown => e
209+
logger.error("Unknown error", error: e.message)
210+
raise e.class, e.message
207211
end
208212
end
209213

github_hooks/spec/lib/internal_api/repo_proxy/repo_proxy_server_spec.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,32 @@
217217
end
218218
end
219219

220+
describe "#create" do
221+
before "when unknown remote error is raised" do
222+
allow(InternalApi::RepoProxy::PayloadFactory).to receive(
223+
:create
224+
).and_raise(RepoHost::RemoteException::Unknown, "Oops")
225+
226+
owner = FactoryBot.create(:user, :github_connection)
227+
repository = FactoryBot.create(:repository, :name => "sandbox", :owner => "renderedtext",
228+
:integration_type => "github_app")
229+
project = FactoryBot.create(:project, :repository => repository)
230+
@req = InternalApi::RepoProxy::CreateRequest.new(
231+
:project_id => project.id,
232+
:requester_id => owner.id,
233+
:git => InternalApi::RepoProxy::CreateRequest::Git.new(
234+
reference: "refs/pull/123"
235+
)
236+
)
237+
end
238+
239+
it "returns an unknown error" do
240+
expect do
241+
server.create(@req, call)
242+
end.to raise_error(GRPC::Unknown)
243+
end
244+
end
245+
220246
describe "#schedule_blocked_hook" do
221247
context "when the hook is present" do
222248
before do

github_hooks/spec/lib/repo_host/github/client_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,19 @@
108108
end
109109
end
110110

111+
context "when unhandled octokit exception occurs" do
112+
before do
113+
allow_any_instance_of(Octokit::Client).to receive(:repositories)
114+
.and_raise(Octokit::TooManyLoginAttempts)
115+
end
116+
117+
it "raises semaphore's RepoHost::RemoteException::NotFound" do
118+
expect do
119+
@client.repositories
120+
end.to raise_error(RepoHost::RemoteException::Unknown)
121+
end
122+
end
123+
111124
context "when repository hook already exists on GitHub" do
112125
before do
113126
allow_any_instance_of(Octokit::Client).to receive(:create_hook)

github_hooks/spec/lib/semaphore/repo_host/hooks/handler_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,22 @@
309309
end
310310
end
311311

312+
context "and the pull-request get throws unknown error" do
313+
before do
314+
allow(repo_host).to receive(:validate_token_presence!)
315+
allow(repo_host).to receive(:pull_request).and_raise(::RepoHost::RemoteException::Unknown,
316+
"Oops")
317+
end
318+
319+
it "logs the error and raises again" do
320+
expect(@logger).to receive(:error).with("Unknown error", error: "Oops")
321+
322+
expect do
323+
described_class.run(@workflow, @logger)
324+
end.to raise_error(RepoHost::RemoteException::Unknown)
325+
end
326+
end
327+
312328
context "and the pull-request is eventually found, but non mergeable" do
313329
before do
314330
allow(repo_host).to receive(:validate_token_presence!)

0 commit comments

Comments
 (0)