Skip to content

Commit

Permalink
Lcov report (#2)
Browse files Browse the repository at this point in the history
* execute node bin

* calculate percentage for lcov file

* install node in docker image

* use relative path to bin folder

* update readme
  • Loading branch information
MiguelSavignano authored Nov 3, 2019
1 parent 6dc7a86 commit d734a59
Show file tree
Hide file tree
Showing 7 changed files with 382 additions and 28 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
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"]
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,26 @@ A GitHub Action that check minimum coverage percentage!

### Usage

#### [Simplecov](https://github.com/colszowka/simplecov)
#### Lcov

```yml
- uses: devmasx/coverage-check-action@v1.0.1
- uses: devmasx/coverage-check-action@v1.1.0
with:
result_path: coverage/.last_run.json
type: lcov
result_path: coverage/example.lcov
min_coverage: 90
token: ${{secrets.GITHUB_TOKEN}}
```
#### [Simplecov](https://github.com/colszowka/simplecov)
```yml
- uses: devmasx/[email protected]
with:
type: simplecov
result_path: coverage/.last_run.json
min_coverage: 90
token: ${{secrets.GITHUB_TOKEN}}
```
## Screenshots
Expand Down
4 changes: 2 additions & 2 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ branding:
color: "green"
inputs:
type:
description: "simplecov | jest"
description: "lcov | simplecov"
required: true
default: "simplecov"
default: "lcov"
token:
description: "Github token for create checks"
required: true
Expand Down
129 changes: 129 additions & 0 deletions bin/lcov-parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
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])
59 changes: 36 additions & 23 deletions lib/coverage_report.rb
Original file line number Diff line number Diff line change
@@ -1,33 +1,46 @@
# frozen_string_literal: true

class CoverageReport
def self.generate(type, report_path, data)
if type == 'simplecov'
simplecov(report_path, data)
elsif type == 'jest'
jest(report_path, data)
else
raise 'InvalidCoverageReportType'
class << self
def generate(type, report_path, data)
if type == 'simplecov'
simplecov(report_path, data)
elsif type == 'lcov'
lcov(report_path, data)
else
raise 'InvalidCoverageReportType'
end
end
end

def self.simplecov(report_path, data)
report = read_json(report_path)
minumum_percent = data[:min]
covered_percent = report.dig('result', 'covered_percent')
{ 'lines' => { 'covered_percent' => covered_percent, 'minumum_percent' => minumum_percent } }
end
def simplecov(report_path, data)
report = read_json(report_path)
minumum_percent = data[:min]
covered_percent = report.dig('result', 'covered_percent')
{ 'lines' => { 'covered_percent' => covered_percent, 'minumum_percent' => minumum_percent } }
end

def self.jest(report_path, data)
report = read_json(report_path)
minumum_percent = data[:min]
covered_percent = report.dig('result', 'covered_percent')
{ 'lines' => { 'covered_percent' => covered_percent, 'minumum_percent' => minumum_percent } }
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 } }
end

private
private

def self.read_json(path)
JSON.parse(File.read(path))
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
end
end
5 changes: 5 additions & 0 deletions spec/coverage_report_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@
result = CoverageReport.simplecov('./spec/fixtures/simplecov.json', min: 80)
expect(result['lines']['covered_percent']).to eq(80.5)
end

it '.lcov' do
result = CoverageReport.lcov('./spec/fixtures/example.lcov', min: 80)
expect(result['lines']['covered_percent']).to eq(85.61)
end
end
Loading

0 comments on commit d734a59

Please sign in to comment.