Skip to content

Commit

Permalink
Create scm report statuses when failing
Browse files Browse the repository at this point in the history
When the workflow run gets errors when sending the statuses to the SCM
we save the response into a new ScmStatusReport object so we can look at
it from the Workflow Run's detail page and be able to debug it.
  • Loading branch information
danidoni committed May 30, 2022
1 parent 03b986d commit 746255f
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 6 deletions.
6 changes: 3 additions & 3 deletions src/api/app/controllers/trigger_workflow_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ def create
if validation_errors.none?
@workflow_run.update(status: 'success', response_body: render_ok)
else
@workflow_run.update_to_fail(render_error(status: 400, message: validation_errors.to_sentence))
@workflow_run.update_as_failed(render_error(status: 400, message: validation_errors.to_sentence))
end
end
rescue APIError => e
@workflow_run.update_to_fail(render_error(status: e.status, errorcode: e.errorcode, message: e.message))
@workflow_run.update_as_failed(render_error(status: e.status, errorcode: e.errorcode, message: e.message))
end
end

Expand All @@ -34,7 +34,7 @@ def set_scm_event
def validate_scm_event
return if @gitlab_event.present? || @github_event.present?

@workflow_run.update_to_fail(
@workflow_run.update_as_failed(
render_error(
status: 400,
errorcode: 'bad_request',
Expand Down
27 changes: 26 additions & 1 deletion src/api/app/models/workflow_run.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# rubocop:disable Metrics/ClassLength
class WorkflowRun < ApplicationRecord
SOURCE_NAME_PAYLOAD_MAPPING = {
'pull_request' => ['pull_request', 'number'],
Expand All @@ -13,6 +14,15 @@ class WorkflowRun < ApplicationRecord
'Push Hook' => ['commits', 0, 'url']
}.freeze

PERMITTED_OPTIONS = [
# Permitted keys for GitHub
:api_endpoint, :target_repository_full_name, :commit_sha,
# Permitted keys for GitLab
:endpoint, :project_id, :commit_sha,
# both GitHub and GitLab
:state, :status_options
].freeze

validates :response_url, length: { maximum: 255 }
validates :request_headers, :status, presence: true

Expand All @@ -28,10 +38,24 @@ class WorkflowRun < ApplicationRecord
fail: 2
}

def update_to_fail(message)
# Marks the workflow run as failed and records the relevant debug information in response_body
def update_as_failed(message)
update(response_body: message, status: 'fail')
end

# Stores debug info to help figure out what went wrong when trying to save a Status in the SCM.
# Marks the workflow run as failed also.
def save_scm_report_failure(message, options)
scm_status_reports.create(response_body: message,
request_parameters: JSON.generate(options.slice(PERMITTED_OPTIONS)))
update(status: 'fail')
end

# Stores info from a succesful SCM status report
def save_scm_report_success(options)
scm_status_reports.create(request_parameters: JSON.generate(options.slice(PERMITTED_OPTIONS)))
end

def payload
JSON.parse(request_payload)
rescue JSON::ParserError
Expand Down Expand Up @@ -116,6 +140,7 @@ def merge_request_with_allowed_action
ScmWebhook::ALLOWED_MERGE_REQUEST_ACTIONS.include?(payload.dig('object_attributes', 'action'))
end
end
# rubocop:enable Metrics/ClassLength

# == Schema Information
#
Expand Down
17 changes: 16 additions & 1 deletion src/api/app/services/scm_exception_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ def initialize(event_payload, event_subscription_payload, scm_token, workflow_ru
private

def log_to_workflow_run(exception, scm)
@workflow_run.update_to_fail("Failed to report back to #{scm}: #{ScmExceptionMessage.for(exception: exception, scm: scm)}")
if @event_payload[:project] && @event_payload[:package]
target_url = Rails.application.routes.url_helpers.package_show_url(@event_payload[:project],
@event_payload[:package],
host: Configuration.obs_url)
end
@workflow_run.save_scm_report_failure("Failed to report back to #{scm}: #{ScmExceptionMessage.for(exception: exception, scm: scm)}",
{
api_endpoint: @event_subscription_payload[:api_endpoint],
target_repository_full_name: @event_subscription_payload[:target_repository_full_name],
commit_sha: @event_subscription_payload[:commit_sha],
state: @state,
status_options: {
context: "OBS: #{@event_payload[:package]} - #{@event_payload[:repository]}/#{@event_payload[:arch]}",
target_url: target_url
}
})
end
end
20 changes: 19 additions & 1 deletion src/api/app/services/scm_status_reporter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ def initialize(event_payload, event_subscription_payload, scm_token, event_type
@state = event_type.nil? ? 'pending' : scm_final_state(event_type)
end

# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def call
if github?
github_client = Octokit::Client.new(access_token: @scm_token, api_endpoint: @event_subscription_payload[:api_endpoint])
Expand All @@ -24,6 +26,7 @@ def call
@state,
status_options)
end
@workflow_run.save_scm_report_success(request_context) if @workflow_run.present?
rescue Octokit::InvalidRepository => e
package = Package.find_by_project_and_name(@event_payload[:project], @event_payload[:package])
return if package.blank?
Expand All @@ -33,12 +36,17 @@ def call

EventSubscription.where(channel: 'scm', token: tokens, package: package).delete_all

@workflow_run.update_to_fail("Failed to report back to GitHub: #{e.message}") if @workflow_run.present?
if @workflow_run.present?
@workflow_run.save_scm_report_failure("Failed to report back to GitHub: #{e.message}",
request_context)
end
rescue Octokit::Error, Gitlab::Error::Error => e
rescue_with_handler(e) || raise(e)
rescue Faraday::ConnectionFailed => e
@workflow_run.update_to_fail("Failed to report back to GitHub: #{e.message}")
end
# rubocop:enable Metrics/PerceivedComplexity
# rubocop:enable Metrics/CyclomaticComplexity

private

Expand All @@ -64,4 +72,14 @@ def scm_final_state(event_type)
'pending'
end
end

def request_context
{
api_endpoint: @event_subscription_payload[:api_endpoint],
target_repository_full_name: @event_subscription_payload[:target_repository_full_name],
commit_sha: @event_subscription_payload[:commit_sha],
state: @state,
status_options: status_options
}
end
end

0 comments on commit 746255f

Please sign in to comment.