parent
97fef59c82
commit
b796f9a6dd
58
lib/github_check_run_service.rb
Normal file
58
lib/github_check_run_service.rb
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class GithubCheckRunService
|
||||||
|
CHECK_NAME = 'Rubocop'
|
||||||
|
|
||||||
|
def initialize(report, github_data, report_adapter)
|
||||||
|
@report = report
|
||||||
|
@github_data = github_data
|
||||||
|
@report_adapter = report_adapter
|
||||||
|
@client = GithubClient.new(@github_data[:token], user_agent: 'rubocop-action')
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
id = @client.post(
|
||||||
|
endpoint_url,
|
||||||
|
create_check_payload
|
||||||
|
)['id']
|
||||||
|
@summary = @report_adapter.summary(@report)
|
||||||
|
@annotations = @report_adapter.annotations(@report)
|
||||||
|
@conclusion = @report_adapter.conslusion(@report)
|
||||||
|
|
||||||
|
@client.patch(
|
||||||
|
"#{endpoint_url}/#{id}",
|
||||||
|
update_check_payload
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def endpoint_url
|
||||||
|
"/repos/#{@github_data[:owner]}/#{@github_data[:repo]}/check-runs"
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_check_payload
|
||||||
|
{
|
||||||
|
name: CHECK_NAME,
|
||||||
|
head_sha: @github_data[:sha],
|
||||||
|
status: 'in_progress',
|
||||||
|
started_at: Time.now.iso8601
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_check_payload
|
||||||
|
{
|
||||||
|
name: CHECK_NAME,
|
||||||
|
head_sha: @github_data[:sha],
|
||||||
|
status: 'completed',
|
||||||
|
completed_at: Time.now.iso8601,
|
||||||
|
conclusion: @conclusion,
|
||||||
|
output: {
|
||||||
|
title: CHECK_NAME,
|
||||||
|
summary: @summary,
|
||||||
|
annotations: @annotations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
40
lib/github_client.rb
Normal file
40
lib/github_client.rb
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class GithubClient
|
||||||
|
def initialize(github_token, user_agent: 'ruby')
|
||||||
|
@github_token = github_token
|
||||||
|
@user_agent = user_agent
|
||||||
|
end
|
||||||
|
|
||||||
|
def patch(url, body = {})
|
||||||
|
request_http do |http|
|
||||||
|
http.patch(url, body.to_json, headers)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def post(url, body = {})
|
||||||
|
request_http do |http|
|
||||||
|
http.post(url, body.to_json, headers)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def headers
|
||||||
|
@headers ||= {
|
||||||
|
"Content-Type": 'application/json',
|
||||||
|
"Accept": 'application/vnd.github.antiope-preview+json',
|
||||||
|
"Authorization": "Bearer #{@github_token}",
|
||||||
|
"User-Agent": @user_agent
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def request_http
|
||||||
|
http = Net::HTTP.new('api.github.com', 443)
|
||||||
|
http.use_ssl = true
|
||||||
|
response = yield(http)
|
||||||
|
raise "#{response.message}: #{response.body}" if response.code.to_i >= 300
|
||||||
|
|
||||||
|
JSON.parse(response.body)
|
||||||
|
end
|
||||||
|
end
|
||||||
145
lib/index.rb
145
lib/index.rb
@ -1,134 +1,29 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'net/http'
|
require 'net/http'
|
||||||
require 'json'
|
require 'json'
|
||||||
require 'time'
|
require 'time'
|
||||||
|
require_relative './report_adapter'
|
||||||
|
require_relative './github_check_run_service'
|
||||||
|
require_relative './github_client'
|
||||||
|
|
||||||
@GITHUB_SHA = ENV["GITHUB_SHA"]
|
def read_json(path)
|
||||||
@GITHUB_EVENT_PATH = ENV["GITHUB_EVENT_PATH"]
|
JSON.parse(File.read(path))
|
||||||
@GITHUB_TOKEN = ENV["GITHUB_TOKEN"]
|
end
|
||||||
@GITHUB_WORKSPACE = ENV["GITHUB_WORKSPACE"]
|
|
||||||
|
|
||||||
@event = JSON.parse(File.read(ENV["GITHUB_EVENT_PATH"]))
|
@event_json = read_json(ENV['GITHUB_EVENT_PATH']) if ENV['GITHUB_EVENT_PATH']
|
||||||
@repository = @event["repository"]
|
@github_data = {
|
||||||
@owner = @repository["owner"]["login"]
|
sha: ENV['GITHUB_SHA'],
|
||||||
@repo = @repository["name"]
|
token: ENV['GITHUB_TOKEN'],
|
||||||
@conclusion = "success"
|
owner: ENV['GITHUB_REPOSITORY_OWNER'] || @event_json.dig('repository', 'owner', 'login'),
|
||||||
@check_name = "Rubocop"
|
repo: ENV['GITHUB_REPOSITORY_NAME'] || @event_json.dig('repository', 'name')
|
||||||
@headers = {
|
|
||||||
"Content-Type": 'application/json',
|
|
||||||
"Accept": 'application/vnd.github.antiope-preview+json',
|
|
||||||
"Authorization": "Bearer #{@GITHUB_TOKEN}",
|
|
||||||
"User-Agent": 'rubocop-action'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def create_check
|
@report =
|
||||||
body = {
|
if ENV['REPORT_PATH']
|
||||||
"name" => @check_name,
|
read_json(ENV['REPORT_PATH'])
|
||||||
"head_sha" => @GITHUB_SHA,
|
else
|
||||||
"status" => "in_progress",
|
Dir.chdir(ENV['GITHUB_WORKSPACE']) { JSON.parse(`rubocop -f json`) }
|
||||||
"started_at" => Time.now.iso8601
|
|
||||||
}
|
|
||||||
|
|
||||||
http = Net::HTTP.new('api.github.com', 443)
|
|
||||||
http.use_ssl = true
|
|
||||||
path = "/repos/#{@owner}/#{@repo}/check-runs"
|
|
||||||
|
|
||||||
resp = http.post(path, body.to_json, @headers)
|
|
||||||
|
|
||||||
if resp.code.to_i >= 300
|
|
||||||
raise resp.message
|
|
||||||
end
|
end
|
||||||
|
|
||||||
data = JSON.parse(resp.body)
|
GithubCheckRunService.new(@report, @github_data, ReportAdapter).run
|
||||||
return data["id"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_check(id, conclusion, output)
|
|
||||||
body = {
|
|
||||||
"name" => @check_name,
|
|
||||||
"completed_at" => Time.now.iso8601,
|
|
||||||
"conclusion" => conclusion,
|
|
||||||
"output" => output
|
|
||||||
}
|
|
||||||
|
|
||||||
http = Net::HTTP.new('api.github.com', 443)
|
|
||||||
http.use_ssl = true
|
|
||||||
path = "/repos/#{@owner}/#{@repo}/check-runs/#{id}"
|
|
||||||
resp = http.patch(path, body.to_json, @headers)
|
|
||||||
|
|
||||||
if resp.code.to_i >= 300
|
|
||||||
raise resp.message
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@annotation_levels = {
|
|
||||||
"refactor" => 'failure',
|
|
||||||
"convention" => 'failure',
|
|
||||||
"warning" => 'warning',
|
|
||||||
"error" => 'failure',
|
|
||||||
"fatal" => 'failure'
|
|
||||||
}
|
|
||||||
|
|
||||||
def run_rubocop
|
|
||||||
annotations = annotation_messages
|
|
||||||
|
|
||||||
output = {
|
|
||||||
"title": @check_name,
|
|
||||||
"summary": "#{annotations.size} offense(s) found",
|
|
||||||
"annotations" => annotations
|
|
||||||
}
|
|
||||||
|
|
||||||
return { "output" => output, "conclusion" => @conclusion }
|
|
||||||
end
|
|
||||||
|
|
||||||
def annotation_messages
|
|
||||||
errors = nil
|
|
||||||
count = 0
|
|
||||||
annotation_list = []
|
|
||||||
|
|
||||||
Dir.chdir(@GITHUB_WORKSPACE) {
|
|
||||||
errors = JSON.parse(`rubocop --format json`)
|
|
||||||
}
|
|
||||||
|
|
||||||
errors["files"].each do |file|
|
|
||||||
path = file["path"]
|
|
||||||
offenses = file["offenses"]
|
|
||||||
|
|
||||||
offenses.each do |offense|
|
|
||||||
severity = offense["severity"]
|
|
||||||
message = offense["message"]
|
|
||||||
location = offense["location"]
|
|
||||||
annotation_level = @annotation_levels[severity]
|
|
||||||
count = count + 1
|
|
||||||
|
|
||||||
return annotation_list if count == 48
|
|
||||||
|
|
||||||
if annotation_level == "failure"
|
|
||||||
@conclusion = "failure"
|
|
||||||
end
|
|
||||||
|
|
||||||
annotation_list.push({
|
|
||||||
"path" => path,
|
|
||||||
"start_line" => location["start_line"],
|
|
||||||
"end_line" => location["start_line"],
|
|
||||||
"annotation_level": annotation_level,
|
|
||||||
"message" => message
|
|
||||||
})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return annotation_list
|
|
||||||
end
|
|
||||||
|
|
||||||
def run
|
|
||||||
id = create_check()
|
|
||||||
begin
|
|
||||||
results = run_rubocop()
|
|
||||||
conclusion = results["conclusion"]
|
|
||||||
output = results["output"]
|
|
||||||
update_check(id, conclusion, output)
|
|
||||||
rescue
|
|
||||||
update_check(id, "failure", nil)
|
|
||||||
fail
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
run()
|
|
||||||
|
|||||||
54
lib/report_adapter.rb
Normal file
54
lib/report_adapter.rb
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ReportAdapter
|
||||||
|
class << self
|
||||||
|
CONCLUSION_TYPES = { failure: 'failure', success: 'success' }.freeze
|
||||||
|
ANNOTATION_LEVELS = {
|
||||||
|
'refactor' => 'failure',
|
||||||
|
'convention' => 'failure',
|
||||||
|
'warning' => 'warning',
|
||||||
|
'error' => 'failure',
|
||||||
|
'fatal' => 'failure'
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
def conslusion(report)
|
||||||
|
return CONCLUSION_TYPES[:failure] if total_offenses(report).positive?
|
||||||
|
|
||||||
|
CONCLUSION_TYPES[:success]
|
||||||
|
end
|
||||||
|
|
||||||
|
def summary(report)
|
||||||
|
"#{total_offenses(report)} offense(s) found"
|
||||||
|
end
|
||||||
|
|
||||||
|
def annotations(report)
|
||||||
|
annotation_list = []
|
||||||
|
count = 0
|
||||||
|
report['files'].each do |file|
|
||||||
|
file['offenses'].each do |offense|
|
||||||
|
count += 1
|
||||||
|
return annotation_list if count == 48
|
||||||
|
|
||||||
|
location = offense['location']
|
||||||
|
annotation_list.push({
|
||||||
|
'path' => file['path'],
|
||||||
|
'start_line' => location['start_line'],
|
||||||
|
'end_line' => location['last_line'],
|
||||||
|
'annotation_level' => annotation_level(offense['severity']),
|
||||||
|
'message' => offense['message']
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def annotation_level(severity)
|
||||||
|
ANNOTATION_LEVELS[severity]
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_offenses(report)
|
||||||
|
report.dig('summary', 'offense_count')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
3301
spec/fixtures/report.json
vendored
Normal file
3301
spec/fixtures/report.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
spec/github_check_run_service_spec.rb
Normal file
18
spec/github_check_run_service_spec.rb
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
require './spec/spec_helper'
|
||||||
|
|
||||||
|
describe GithubCheckRunService do
|
||||||
|
let(:rubocop_report) { JSON(File.read('./spec/fixtures/report.json')) }
|
||||||
|
let(:github_data) { { sha: 'sha', token: 'token', owner: 'owner', repo: 'repository_name' } }
|
||||||
|
let(:service) { GithubCheckRunService.new(rubocop_report, github_data, ReportAdapter) }
|
||||||
|
|
||||||
|
it '#run' do
|
||||||
|
stub_request(:any, 'https://api.github.com/repos/owner/repository_name/check-runs/id')
|
||||||
|
.to_return(status: 200, body: '{}')
|
||||||
|
|
||||||
|
stub_request(:any, 'https://api.github.com/repos/owner/repository_name/check-runs')
|
||||||
|
.to_return(status: 200, body: '{"id": "id"}')
|
||||||
|
|
||||||
|
output = service.run
|
||||||
|
expect(output).to be_a(Hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
30
spec/report_adapter_spec.rb
Normal file
30
spec/report_adapter_spec.rb
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
require './spec/spec_helper'
|
||||||
|
|
||||||
|
describe ReportAdapter do
|
||||||
|
let(:rubocop_report) {
|
||||||
|
JSON(File.read('./spec/fixtures/report.json'))
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:adapter) { ReportAdapter }
|
||||||
|
|
||||||
|
it '.conslusion' do
|
||||||
|
result = adapter.conslusion(rubocop_report)
|
||||||
|
expect(result).to eq('failure')
|
||||||
|
end
|
||||||
|
|
||||||
|
it '.summary' do
|
||||||
|
result = adapter.summary(rubocop_report)
|
||||||
|
expect(result).to eq('201 offense(s) found')
|
||||||
|
end
|
||||||
|
|
||||||
|
it '.annotations' do
|
||||||
|
result = adapter.annotations(rubocop_report)
|
||||||
|
expect(result.first).to eq({
|
||||||
|
'path' => 'Gemfile',
|
||||||
|
'start_line' => 1,
|
||||||
|
'end_line' => 1,
|
||||||
|
'annotation_level' => 'failure',
|
||||||
|
'message' => 'Missing magic comment `# frozen_string_literal: true`.'
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
6
spec/spec_helper.rb
Normal file
6
spec/spec_helper.rb
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
require 'webmock/rspec'
|
||||||
|
require 'json'
|
||||||
|
require 'pry'
|
||||||
|
require './lib/report_adapter'
|
||||||
|
require './lib/github_check_run_service'
|
||||||
|
require './lib/github_client'
|
||||||
Reference in New Issue
Block a user