Compare commits

..

9 Commits

Author SHA1 Message Date
miguemasx
713e95c6a9 update README 2020-03-17 02:53:38 +01:00
miguemasx
1faf8632d3 covered_percent 2020-03-17 02:49:43 +01:00
miguemasx
251c13c7f6 read from github workspace 2020-03-17 02:48:02 +01:00
miguemasx
2ada319a08 debug 2020-03-17 02:03:48 +01:00
miguemasx
ee391c84c4 lcov report path 2020-03-17 01:24:43 +01:00
miguemasx
5d3df49d00 use github workspace path 2020-03-17 01:19:42 +01:00
miguemasx
0bb92bcdfe fix test 2020-03-17 01:03:19 +01:00
miguemasx
6412a29aa9 delete nodejs script 2020-03-17 00:57:45 +01:00
miguemasx
718cf309b6 parse lcov file in ruby 2020-03-17 00:56:35 +01:00
13 changed files with 64 additions and 189 deletions

View File

@ -1,9 +1,5 @@
# Changelog
## v1.2.0
- Added the coverage percent to result title on Check [#4](https://github.com/devmasx/coverage-check-action/pull/4)
## v1.1.0
- Lcov

View File

@ -1,8 +1,5 @@
FROM ruby:2.6.5-alpine
RUN apk add --update nodejs
COPY lib /action/lib
COPY bin /action/bin
CMD ["ruby", "/action/lib/index.rb"]

View File

@ -2,43 +2,30 @@
A GitHub Action that check minimum coverage percentage!
This action requires a Github token with `checks:write` scope to allow create the check run using the Github API v3.
But no need to generate any new token, you can use the Github action token (`${{ github.token }}`)
### Usage
#### Lcov
```yml
- uses: devmasx/coverage-check-action@v1.2.0
- uses: actions/checkout@v1
- uses: devmasx/coverage-check-action@v1.1.0
with:
type: lcov
result_path: coverage/example.lcov
min_coverage: 90
token: ${{ github.token }}
token: ${{secrets.GITHUB_TOKEN}}
```
#### [Simplecov](https://github.com/colszowka/simplecov)
```yml
- uses: devmasx/coverage-check-action@v1.2.0
- uses: actions/checkout@v1
- uses: devmasx/coverage-check-action@v1.1.0
with:
type: simplecov
result_path: coverage/.last_run.json
min_coverage: 90
token: ${{ github.token }}
```
#### Report name
```yml
- uses: devmasx/coverage-check-action@v1.2.0
with:
type: lcov
result_path: coverage/example.lcov
min_coverage: 90
token: ${{ github.token }}
report_name: "My Github Action Check Name"
token: ${{secrets.GITHUB_TOKEN}}
```
## Screenshots

View File

@ -15,9 +15,6 @@ inputs:
min_coverage:
description: "Minimum coverage"
default: "80"
report_name:
description: "Name of the github action check"
default: "Coverage"
result_path:
description: "Json with coverage result"
required: true

View File

@ -1,129 +0,0 @@
/*
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://yuilibrary.com/license/
*/
var fs = require('fs'),
path = require('path');
/* istanbul ignore next */
var exists = fs.exists || path.exists;
var walkFile = function (str, cb) {
var data = [], item;
['end_of_record'].concat(str.split('\n')).forEach(function (line) {
line = line.trim();
var allparts = line.split(':'),
parts = [allparts.shift(), allparts.join(':')],
lines, fn;
switch (parts[0].toUpperCase()) {
case 'TN':
item.title = parts[1].trim();
break;
case 'SF':
item.file = parts.slice(1).join(':').trim();
break;
case 'FNF':
item.functions.found = Number(parts[1].trim());
break;
case 'FNH':
item.functions.hit = Number(parts[1].trim());
break;
case 'LF':
item.lines.found = Number(parts[1].trim());
break;
case 'LH':
item.lines.hit = Number(parts[1].trim());
break;
case 'DA':
lines = parts[1].split(',');
item.lines.details.push({
line: Number(lines[0]),
hit: Number(lines[1])
});
break;
case 'FN':
fn = parts[1].split(',');
item.functions.details.push({
name: fn[1],
line: Number(fn[0])
});
break;
case 'FNDA':
fn = parts[1].split(',');
item.functions.details.some(function (i, k) {
if (i.name === fn[1] && i.hit === undefined) {
item.functions.details[k].hit = Number(fn[0]);
return true;
}
});
break;
case 'BRDA':
fn = parts[1].split(',');
item.branches.details.push({
line: Number(fn[0]),
block: Number(fn[1]),
branch: Number(fn[2]),
taken: ((fn[3] === '-') ? 0 : Number(fn[3]))
});
break;
case 'BRF':
item.branches.found = Number(parts[1]);
break;
case 'BRH':
item.branches.hit = Number(parts[1]);
break;
}
if (line.indexOf('end_of_record') > -1) {
data.push(item);
item = {
lines: {
found: 0,
hit: 0,
details: []
},
functions: {
hit: 0,
found: 0,
details: []
},
branches: {
hit: 0,
found: 0,
details: []
}
};
}
});
data.shift();
if (data.length) {
cb(null, data);
} else {
cb('Failed to parse string');
}
};
var parse = function (file, cb) {
exists(file, function (x) {
if (!x) {
return walkFile(file, cb);
}
fs.readFile(file, 'utf8', function (err, str) {
walkFile(str, cb);
});
});
};
var path = process.argv[2]
parse(path, function (err, data) {
console.log(JSON.stringify(data, null, 2))
});
// console.log(process.argv[2])

View File

@ -20,25 +20,12 @@ class CoverageReport
end
def lcov(report_path, data)
lcov_result = execute_lcov_parse(report_path)
minumum_percent = data[:min]
{ 'lines' => { 'covered_percent' => lcov_covered_percent(lcov_result), 'minumum_percent' => minumum_percent } }
lcov = LcovParse.new(File.read("/github/workspace/#{report_path}"))
{ 'lines' => { 'covered_percent' => lcov.covered_percent, 'minumum_percent' => data[:min] } }
end
private
def lcov_covered_percent(lcov_result)
lines = lcov_result.map { |r| r['lines']['details'] }.flatten
total_lines = lines.count.to_f.round(2)
covered_lines = lines.select { |r| r['hit'] >= 1 }.count.to_f
((covered_lines / total_lines) * 100).round(2)
end
def execute_lcov_parse(report_path)
bin_path = "#{File.dirname(__FILE__)}/../bin"
JSON.parse(`node #{bin_path}/lcov-parse.js #{report_path}`)
end
def read_json(path)
JSON.parse(File.read(path))
end

View File

@ -1,10 +1,11 @@
# frozen_string_literal: true
class GithubCheckRunService
def initialize(report, github_data, report_name, report_adapter)
CHECK_NAME = 'Coverage'
def initialize(report, github_data, report_adapter)
@report = report
@github_data = github_data
@report_name = report_name
@report_adapter = report_adapter
@client = GithubClient.new(@github_data[:token], user_agent: 'coverage-action')
end
@ -17,7 +18,6 @@ class GithubCheckRunService
@summary = @report_adapter.summary(@report)
@annotations = @report_adapter.annotations(@report)
@conclusion = @report_adapter.conslusion(@report)
@percent = @report_adapter.lines_covered_percent(@report)
@client.patch(
"#{endpoint_url}/#{id}",
@ -33,7 +33,7 @@ class GithubCheckRunService
def create_check_payload
{
name: @report_name,
name: CHECK_NAME,
head_sha: @github_data[:sha],
status: 'in_progress',
started_at: Time.now.iso8601
@ -42,13 +42,13 @@ class GithubCheckRunService
def update_check_payload
{
name: @report_name,
name: CHECK_NAME,
head_sha: @github_data[:sha],
status: 'completed',
completed_at: Time.now.iso8601,
conclusion: @conclusion,
output: {
title: "#{@report_name} #{@percent}%",
title: CHECK_NAME,
summary: @summary,
annotations: @annotations
}

View File

@ -7,6 +7,7 @@ require_relative './report_adapter'
require_relative './github_check_run_service'
require_relative './github_client'
require_relative './coverage_report'
require_relative './lcov_parse'
def read_json(path)
JSON.parse(File.read(path))
@ -17,14 +18,13 @@ end
sha: ENV['GITHUB_SHA'],
token: ENV['INPUT_TOKEN'],
owner: ENV['GITHUB_REPOSITORY_OWNER'] || @event_json.dig('repository', 'owner', 'login'),
repo: ENV['GITHUB_REPOSITORY_NAME'] || @event_json.dig('repository', 'name'),
repo: ENV['GITHUB_REPOSITORY_NAME'] || @event_json.dig('repository', 'name')
}
@coverage_type = ENV['INPUT_TYPE']
@report_path = ENV['INPUT_RESULT_PATH']
@report_name = ENV['INPUT_REPORT_NAME']
@data = { min: ENV['INPUT_MIN_COVERAGE'] }
@report = CoverageReport.generate(@coverage_type, @report_path, @data)
GithubCheckRunService.new(@report, @github_data, @report_name, ReportAdapter).run
GithubCheckRunService.new(@report, @github_data, ReportAdapter).run

40
lib/lcov_parse.rb Normal file
View File

@ -0,0 +1,40 @@
class LcovParse
def initialize(lcov_content)
@lcov = lcov_content
end
def to_json
@to_json ||= @lcov.split("end_of_record").map do |file_item|
file_item.split("\n").reduce({}) do |memo, item|
type, value = item.split(":")
case type
when "DA", "FNF", "FNH", "LF", "LH", "FN", "FNDA", "BRDA", "BRF", "BRH"
memo[type] = [] unless memo[type]
memo[type].push(value&.strip)
when "TN", "SF"
memo[type] = value
end
memo
end
end
end
def lines
@lines ||=
to_json.map{|it| it["DA"] }
.flatten.compact
.map{|it| it.split(",").last }
end
def total_lines
lines.count
end
def covered_lines
lines.select{|it| it == "1" }.count
end
def covered_percent
((covered_lines / total_lines.to_f) * 100).round(2)
end
end

View File

@ -18,16 +18,16 @@ class ReportAdapter
[]
end
def lines_covered_percent(report)
@lines_covered_percent ||= report.dig('lines', 'covered_percent')
end
private
def table_head
"| Type | covered | minimum |\n| ----- | ------- | ------- |"
end
def lines_covered_percent(report)
@lines_covered_percent ||= report.dig('lines', 'covered_percent')
end
def lines_minimum_percent(report)
@lines_minimum_percent ||= report.dig('lines', 'minumum_percent')
end

View File

@ -10,6 +10,6 @@ describe CoverageReport do
it '.lcov' do
result = CoverageReport.lcov('./spec/fixtures/example.lcov', min: 80)
expect(result['lines']['covered_percent']).to eq(85.61)
expect(result['lines']['covered_percent']).to eq(84.85)
end
end

View File

@ -7,8 +7,7 @@ describe GithubCheckRunService do
{ 'lines' => { 'covered_percent' => 80, 'minumum_percent' => 80 } }
end
let(:github_data) { { sha: 'sha', token: 'token', owner: 'owner', repo: 'repository_name' } }
let(:report_name) { 'Coverage' }
let(:service) { GithubCheckRunService.new(report, github_data, report_name, ReportAdapter) }
let(:service) { GithubCheckRunService.new(report, github_data, ReportAdapter) }
it '#run' do
stub_request(:any, 'https://api.github.com/repos/owner/repository_name/check-runs/id')

View File

@ -7,3 +7,4 @@ require './lib/report_adapter'
require './lib/github_check_run_service'
require './lib/github_client'
require './lib/coverage_report'
require './lib/lcov_parse'