Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SimpleCov coverage format conversion example #173

Merged
merged 1 commit into from
Apr 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions simplecov/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# OPA Test Coverage to SimpleCov Format

Example Rego code to transform the OPA test coverage JSON report to
the [JSON representation](https://github.com/codeclimate-community/simplecov_json_formatter)
of the [SimpleCov](https://github.com/simplecov-ruby/simplecov) coverage report format.

## Why?

SimpleCov JSON is one of the supported report formats for
[AWS CodeBuild](https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html#reports-buildspec-file),
and likely other CI/CD tools as well.

## Example

Simply pipe the output of `opa test --coverage` into `opa eval` with the `simplecov.rego` file loaded:

```shell
$ opa test --coverage example \
| opa eval --format pretty \
--stdin-input \
--data simplecov.rego \
data.simplecov.from_opa
```
**Output**
```json
{
"coverage": {
"example/policy.rego": {
"lines": [
null,
null,
1,
1,
null,
null,
0,
0
]
},
"example/policy_test.rego": {
"lines": [
null,
null,
1,
1
]
}
}
}
```

## Caveats

The OPA coverage report format does not report total number of lines in a file,
so the report will stop at the last occurence of a covered or not covered line.
9 changes: 9 additions & 0 deletions simplecov/example/policy.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package policy

deny["foo"] {
input.foo == "bar"
}

deny["bar"] {
input.bar == "foo"
}
5 changes: 5 additions & 0 deletions simplecov/example/policy_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package policy

test_deny {
deny with input as {"foo": "bar"}
}
49 changes: 49 additions & 0 deletions simplecov/simplecov.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package simplecov

import future.keywords

from_opa := {
"coverage": coverage
}

coverage[file] = obj {
some file, report in input.files
obj := {
"lines": to_lines(report)
}
}

covered_map(report) = cm {
covered := object.get(report, "covered", [])
cm := {line: 1 | some item in covered
some line in numbers.range(item.start.row, item.end.row)}
}

not_covered_map(report) = ncm {
not_covered := object.get(report, "not_covered", [])
ncm := {line: 0 | some item in not_covered
some line in numbers.range(item.start.row, item.end.row)}
}

to_lines(report) = lines {
cm := covered_map(report)
ncm := not_covered_map(report)
keys := sort([line | some line, _ in object.union(cm, ncm)])
last := keys[count(keys) - 1]

lines := [value | some i in numbers.range(1, last)
value := to_value(cm, ncm, i)]
}

to_value(cm, _, line) = 1 {
cm[line]
}

to_value(_, ncm, line) = 0 {
ncm[line]
}

to_value(cm, ncm, line) = null {
not cm[line]
not ncm[line]
}