Skip to content

Commit

Permalink
feat: jacoco report parsing step version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
thomashorta committed Dec 1, 2021
1 parent eae6ed3 commit 2680b2d
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 58 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
.bitrise*
.gows.user.yml
.DS_Store
.envstore.yml
_temp/
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
# JaCoCo Report Parser

Fill description with what step does, services and tools used, configuration info, inputs, and troubleshooting.
This step parses a JaCoCo generated XML report in the `jacoco_report_path` and outputs the coverage percentages in a String format to environment / output variables to be used in other steps.

It basically gets the top-level counter information for each coverage type and calculates de percentage by doing `covered` / `covered` + `missed`.

Input:
`jacoco_report_path` receives the reported file path (it must be an xml)

Outputs:
`JACOCO_INSTRUCTION_COVERAGE` contains the instruction coverage percentage calculated from the report
`JACOCO_BRANCH_COVERAGE` contains the branch coverage percentage calculated from the report
`JACOCO_LINE_COVERAGE` contains the line coverage percentage calculated from the report
`JACOCO_COMPLEXITY_COVERAGE` contains the complexity coverage percentage calculated from the report
`JACOCO_METHOD_COVERAGE` contains the method coverage percentage calculated from the report
`JACOCO_CLASS_COVERAGE` contains the class coverage percentage calculated from the report


## How to use this Step
Expand Down
27 changes: 12 additions & 15 deletions bitrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,15 @@ default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git

app:
envs:
# An example secret param, define it (A_SECRET_PARAM) in .bitrise.secrets.yml
- A_SECRET_PARAM: $A_SECRET_PARAM
# If you want to share this step into a StepLib
- BITRISE_STEP_ID: jacoco-report-parser
- BITRISE_STEP_VERSION: "0.0.1"
- BITRISE_STEP_VERSION: "1.0.0"
- BITRISE_STEP_GIT_CLONE_URL: https://github.com/thomashorta/bitrise-step-jacoco-report-parser.git
- MY_STEPLIB_REPO_FORK_GIT_URL: $MY_STEPLIB_REPO_FORK_GIT_URL

workflows:
test:
steps:
- script:
inputs:
- content: |
#!/bin/bash
echo "Just an example 'secrets' print."
echo "The value of 'A_SECRET_PARAM' is: $A_SECRET_PARAM"
- change-workdir:
title: Switch working dir to test / _tmp dir
description: |-
Expand All @@ -34,18 +26,23 @@ workflows:
- path::./:
title: Step Test
description: |-
The example input has a default value,
you can overwrite it if you want to, just like we did below,
but the step would use the default value specified in the `step.yml`
file if you would not specify another value.
Test the Jacoco Report Parser Step.
The sample jacoco.xml used here is from the sample repository
at https://github.com/thomashorta/newsapi_sample_android
run_if: true
inputs:
- example_step_input: Example Step Input's value
- jacoco_report_path: $BITRISE_STEP_SOURCE_DIR/reports/jacoco.xml
- script:
inputs:
- content: |
#!/bin/bash
echo "This output was generated by the Step (EXAMPLE_STEP_OUTPUT): $EXAMPLE_STEP_OUTPUT"
echo "(JACOCO_INSTRUCTION_COVERAGE): $JACOCO_INSTRUCTION_COVERAGE"
echo "(JACOCO_BRANCH_COVERAGE): $JACOCO_BRANCH_COVERAGE"
echo "(JACOCO_LINE_COVERAGE): $JACOCO_LINE_COVERAGE"
echo "(JACOCO_COMPLEXITY_COVERAGE): $JACOCO_COMPLEXITY_COVERAGE"
echo "(JACOCO_METHOD_COVERAGE): $JACOCO_METHOD_COVERAGE"
echo "(JACOCO_CLASS_COVERAGE): $JACOCO_CLASS_COVERAGE"
# ----------------------------------------------------------------
Expand Down
130 changes: 113 additions & 17 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,127 @@
package main

import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
)

// Bitrise XML structs
type Report struct {
XMLName xml.Name `xml:"report"`
Name string `xml:"name,attr"`
Counters []Counter `xml:"counter"`
}

type Counter struct {
XMLName xml.Name `xml:"counter"`
Type string `xml:"type,attr"`
Missed int `xml:"missed,attr"`
Covered int `xml:"covered,attr"`
}

// JaCoCo counter types
const Instruction = "INSTRUCTION"
const Branch = "BRANCH"
const Line = "LINE"
const Complexity = "COMPLEXITY"
const Method = "METHOD"
const Class = "CLASS"

// Step outputs
const OutputInstructionCoverage = "JACOCO_INSTRUCTION_COVERAGE"
const OutputBranchCoverage = "JACOCO_BRANCH_COVERAGE"
const OutputLineCoverage = "JACOCO_LINE_COVERAGE"
const OutputComplexityCoverage = "JACOCO_COMPLEXITY_COVERAGE"
const OutputMethodCoverage = "JACOCO_METHOD_COVERAGE"
const OutputClassCoverage = "JACOCO_CLASS_COVERAGE"

var OutputKeys = [...]string{
OutputInstructionCoverage,
OutputBranchCoverage,
OutputLineCoverage,
OutputComplexityCoverage,
OutputMethodCoverage,
OutputClassCoverage,
}

func main() {
fmt.Println("This is the value specified for the input 'example_step_input':", os.Getenv("example_step_input"))

//
// --- Step Outputs: Export Environment Variables for other Steps:
// You can export Environment Variables for other Steps with
// envman, which is automatically installed by `bitrise setup`.
// A very simple example:
cmdLog, err := exec.Command("bitrise", "envman", "add", "--key", "EXAMPLE_STEP_OUTPUT", "--value", "the value you want to share").CombinedOutput()
reportPath := os.Getenv("jacoco_report_path")
reportFormat := reportPath[strings.LastIndex(reportPath, ".")+1:]

if reportFormat != "xml" {
fmt.Println("Only xml is supported at the moment.")
os.Exit(1)
}

// Open xml file
xmlFile, err := os.Open(reportPath)

if err != nil {
fmt.Printf("Failed to expose output with envman, error: %#v | output: %s", err, cmdLog)
fmt.Printf("Failed to open specified file %s\n", reportPath)
os.Exit(1)
}
// You can find more usage examples on envman's GitHub page
// at: https://github.com/bitrise-io/envman

//
// --- Exit codes:
// The exit code of your Step is very important. If you return
// with a 0 exit code `bitrise` will register your Step as "successful".
// Any non zero exit code will be registered as "failed" by `bitrise`.

fmt.Printf("Opened %s\n", reportPath)

defer xmlFile.Close()

fmt.Println("Parsing the report file")

byteValue, _ := ioutil.ReadAll(xmlFile)

var report Report

xml.Unmarshal(byteValue, &report)

coverageMap := map[string]string{}
for _, counter := range report.Counters {
coverage := CalcCoverage(counter.Missed, counter.Covered)
switch counter.Type {
case Instruction:
coverageMap[OutputInstructionCoverage] = coverage
case Branch:
coverageMap[OutputBranchCoverage] = coverage
case Line:
coverageMap[OutputLineCoverage] = coverage
case Complexity:
coverageMap[OutputComplexityCoverage] = coverage
case Method:
coverageMap[OutputMethodCoverage] = coverage
case Class:
coverageMap[OutputClassCoverage] = coverage
}
}

// output all coverages or N/A for the ones not available
for _, key := range OutputKeys {
val, ok := coverageMap[key]
if !ok {
val = "N/A"
}
SetOutput(key, val)
}

fmt.Println("JaCoCo report file parsed and coverage exported")
os.Exit(0)
}

// returns the formatted coverage string, e.g.: 4.50%
func CalcCoverage(missed int, covered int) string {
total := missed + covered
coverage := 100.0 * float64(covered) / float64(total)
return fmt.Sprintf("%.2f%%", coverage)
}

// outputs the desired text to the environment variable
func SetOutput(key string, value string) {
fmt.Printf("Outputing key %s with value %s\n", key, value)
cmdLog, err := exec.Command("bitrise", "envman", "add", "--key", key, "--value", value).CombinedOutput()
if err != nil {
fmt.Printf("Failed to expose output with envman, error: %#v | output: %s\n", err, cmdLog)
os.Exit(1)
}
}
1 change: 1 addition & 0 deletions reports/jacoco.xml

Large diffs are not rendered by default.

114 changes: 89 additions & 25 deletions step.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,24 @@
title: |-
JaCoCo Report Parser
summary: |
Parses a JaCoCo generated report and outputs the code coverage percentages to be used by other steps.
Parse a JaCoCo generated report and output the code coverage percentages to be used by other steps.
description: |
Fill description with what step does, services and tools used, configuration info, inputs, and troubleshooting.
This step parses a JaCoCo generated XML report in the `jacoco_report_path` and outputs the coverage
percentages in a String format to environment / output variables to be used in other steps.
It basically gets the top-level counter information for each coverage type and calculates de percentage
by doing `covered` / `covered` + `missed`.
Input:
`jacoco_report_path` receives the reported file path (it must be an xml)
Outputs:
`JACOCO_INSTRUCTION_COVERAGE` contains the instruction coverage percentage calculated from the report
`JACOCO_BRANCH_COVERAGE` contains the branch coverage percentage calculated from the report
`JACOCO_LINE_COVERAGE` contains the line coverage percentage calculated from the report
`JACOCO_COMPLEXITY_COVERAGE` contains the complexity coverage percentage calculated from the report
`JACOCO_METHOD_COVERAGE` contains the method coverage percentage calculated from the report
`JACOCO_CLASS_COVERAGE` contains the class coverage percentage calculated from the report
website: https://github.com/thomashorta/bitrise-step-jacoco-report-parser
source_code_url: https://github.com/thomashorta/bitrise-step-jacoco-report-parser
support_url: https://github.com/thomashorta/bitrise-step-jacoco-report-parser/issues
Expand All @@ -29,25 +44,24 @@ host_os_tags:
# You can find more information about project type tags in the Step Development Guideline:
# https://github.com/bitrise-io/bitrise/blob/master/_docs/step-development-guideline.md
#
# project_type_tags:
# - ios
# - macos
# - android
# - xamarin
# - react-native
# - cordova
# - ionic
project_type_tags:
- android
- xamarin
- react-native
- cordova
- ionic
- flutter

# Type tags are used for categorizing steps, for easier step discovery in Step Libraries.
# You can find more information about type tags in the Step Development Guideline:
# https://github.com/bitrise-io/bitrise/blob/master/_docs/step-development-guideline.md
type_tags:
- test
- utility

is_requires_admin_user: true
is_requires_admin_user: false
is_always_run: false
is_skippable: false
run_if: ""

deps:
brew:
Expand All @@ -64,24 +78,74 @@ toolkit:


inputs:
- example_step_input: Default Value - you can leave this empty if you want to
- jacoco_report_path: $BITRISE_SOURCE_DIR/build/reports/jacoco.xml
opts:
title: "Example Step Input"
summary: Summary. No more than 2-3 sentences.
is_required: true
title: "The JaCoCo report file path"
summary: Exact path location to the JaCoCo report file (usually points to a jacoco.xml file).
description: |
Description of this input.
The report will be parsed from this input to run this step.
Can be Markdown formatted text.
is_expand: true
is_required: true
value_options: []
Default value: `$BITRISE_SOURCE_DIR/build/reports/jacoco.xml`
outputs:
- EXAMPLE_STEP_OUTPUT:
- JACOCO_INSTRUCTION_COVERAGE:
opts:
title: "Instruction coverage percentage"
summary: Total instruction coverage percentage parsed from the report.
description: |
This is the total instruciton coverage percentage parsed from the report
taking into consideration the report summary for the whole run.
This is calculated by taking the `covered` amount divided by the `covered` + `missed` amount.
It returns "N/A" if the coverage information was not found.
- JACOCO_BRANCH_COVERAGE:
opts:
title: "Branch coverage percentage"
summary: Total branch coverage percentage parsed from the report.
description: |
This is the total branch coverage percentage parsed from the report
taking into consideration the report summary for the whole run.
This is calculated by taking the `covered` amount divided by the `covered` + `missed` amount.
It returns "N/A" if the coverage information was not found.
- JACOCO_LINE_COVERAGE:
opts:
title: "Line coverage percentage"
summary: Total line coverage percentage parsed from the report.
description: |
This is the total line coverage percentage parsed from the report
taking into consideration the report summary for the whole run.
This is calculated by taking the `covered` amount divided by the `covered` + `missed` amount.
It returns "N/A" if the coverage information was not found.
- JACOCO_COMPLEXITY_COVERAGE:
opts:
title: "Complexity coverage percentage"
summary: Total complexity coverage percentage parsed from the report.
description: |
This is the total complexity coverage percentage parsed from the report
taking into consideration the report summary for the whole run.
This is calculated by taking the `covered` amount divided by the `covered` + `missed` amount.
It returns "N/A" if the coverage information was not found.
- JACOCO_METHOD_COVERAGE:
opts:
title: "Method coverage percentage"
summary: Total method coverage percentage parsed from the report.
description: |
This is the total method coverage percentage parsed from the report
taking into consideration the report summary for the whole run.
This is calculated by taking the `covered` amount divided by the `covered` + `missed` amount.
It returns "N/A" if the coverage information was not found.
- JACOCO_CLASS_COVERAGE:
opts:
title: "Example Step Output"
summary: Summary. No more than 2-3 sentences.
title: "Class coverage percentage"
summary: Total class coverage percentage parsed from the report.
description: |
Description of this output.
This is the total class coverage percentage parsed from the report
taking into consideration the report summary for the whole run.
Can be Markdown formatted text.
This is calculated by taking the `covered` amount divided by the `covered` + `missed` amount.
It returns "N/A" if the coverage information was not found.

0 comments on commit 2680b2d

Please sign in to comment.