Github Pull Request: Require 100% Code Coverage
Yesterday we got our API code up to 100% code coverage. For me, it’s one of those things that once you get there, you really don’t want to lose it again. We use Code Climate’s Github integration to ensure that our coverage is at least above 90%, but as far as I know there is no way to set that requirement at 100%.
The CI/CD system that we use is Atlassian Bamboo, and it allows for arbitrary shell scripts to be run during a build. Currently we use that functionality to send updates to the Github API to report success/failure on various build steps. For example:
#!/bin/bash
# cribbed from http://broonix-rants.ghost.io/updating-github-status-from-bamboo/
cd ${bamboo.build.working.directory}
##check for test failures, or that they ran at all.
if test -e "api/test-reports/rspec.xml"; then
if (grep 'failure message' api/test-reports/*.xml 1> /dev/null 2>&1) then
mainJunit=$(find api/test-reports/*.xml -print0 | xargs -0 grep 'failure message' | wc -l)
curl -s -H "Authorization: token <redacted>" --request POST --data '{"state": "failure", "context": "bamboo/tests", "description": "'"${mainJunit}"' Test(s) failed!", "target_url": "${bamboo.buildResultsUrl}"}' https://api.github.com/repos/<user>/<repo>/statuses/${bamboo.repository.revision.number} > /dev/null
else
curl -s -H "Authorization: token <redacted>" --request POST --data '{"state": "success", "context": "bamboo/tests", "description": "Tests Passed", "target_url": "${bamboo.buildResultsUrl}"}' https://api.github.com/repos/<user>/<repo>/statuses/${bamboo.repository.revision.number} > /dev/null
fi
else
curl -s -H "Authorization: token <redacted>" --request POST --data '{"state": "failure", "context": "bamboo/tests", "description": "Error running tests", "target_url": "${bamboo.buildResultsUrl}"}' https://api.github.com/repos/<user>/<repo>/statuses/${bamboo.repository.revision.number} > /dev/null
fi
I figured it shouldn’t be a far reach to do something similar for code coverage. So, I did some digging in the
/coverage
directory of our project and saw: .last_run.json
, and inside:
# coverage/.last_run.json
{
"result": {
"covered_percent": 100.0
}
}
That might be useful!
Now, how to get the percentage out of the json? jq
is great, but I didn’t want to apt-get
yet one more dependency
on our CI server; and, I thought it would be a good opportunity to get some practice with grep
and sed
. I came up
with this:
grep -o '"covered_percent":.*[0-9]*' coverage/.last_run.json | sed 's/"covered_percent": //g' | sed 's/\.[0-9]*//g'
From the file above, this yields:
100
Great!
What this does is, find lines with "covered_percent"
and a number, delete the "covered_percent":
, and delete the
decimal places (bash doesn’t do floats, only integers). There may be a better way to do this, but it works! Now I needed
to integrate it into our build to notify Github whether we maintained 100% coverage or not. Using something like the
above, I came up with this:
#!/bin/bash
coverage=$(grep -o '"covered_percent":.*[0-9]*' api/coverage/.last_run.json | sed 's/"covered_percent": //g' | sed 's/\.[0-9]*//g')
if [ $coverage -ge 100 ]; then
curl -s -H "Authorization: token <redacted>" --request POST --data '{"state": "success", "context": "100% Code Coverage", "description": "Coverage == 100%", "target_url": "${bamboo.buildResultsUrl}"}' https://api.github.com/repos/<user>/<repo>/statuses/${bamboo.repository.revision.number} > /dev/null
else
curl -s -H "Authorization: token <redacted>" --request POST --data '{"state": "failure", "context": "100% Code Coverage", "description": "Coverage < 100%", "target_url": "${bamboo.buildResultsUrl}"}' https://api.github.com/repos/<user>/<repo>/statuses/${bamboo.repository.revision.number} > /dev/null
fi
After completing a build with 100% code coverage, we were able to tell our Github repo to require the
100% Code Coverage
status check, and now all subsequent pull requests will be required to meet 100% code coverage.
Success!