Bitbucket repositoty status badges!
This is a short post to help you set up build status and test coverage badges for your Bitbucket repositories.
Part 1: Just using this solution
Getting the files
- Download the
bitbucket-pipelines.yml
andstatus_badge.sh
files found in this Github gist and add them to your repository:
https://gist.github.com/shaypal5/064dd0254a9f32c7549f8d42c26fef90 - Create a
ci
folder at the root of your repository and move thestatus_badge.sh
file there. Thebitbucket-pipelines.yml
should stay at the root of the repository
Dependecy installation
If your project is essentially a Python package which you install and then test, and you also manage extra_requires
test dependecies, then add the following two dependecies to your extra_requires: {'test': …}
of your setup.py
: pybadges, coverage-badge
If not, the change line 11 at of the bitbucket-pipelines.yml
— that currently installs the Python package at the repository’s root, including its test
dependencies — to the following line:
pip install --user pybadges coverage-badge
Under it, add a line installing your code or its dependecies, as required for testing.
Coverage report
This method assumes you run your tests in some way that generate a .coverage
report file, which is what the coverage-badge
package uses to find out what is your test coverage and generate the badge with.
If you have none, I recommend using pytest
, with the additional depencies of coverage
and pytest-cov
, and to run the pytest
command with the cov
flag: pytest --cov=myproj
.
Setup the required Pipelines variables
Follows steps 1 and 2 here for your repository to populate the BITBUCKET_USERNAME
and BITBUCKET_APP_PASSWORD
variables:
https://support.atlassian.com/bitbucket-cloud/docs/deploy-build-artifacts-to-bitbucket-downloads/
You do not need to follow the later steps, as the bitbucket-pipelines.yml
file already references them. You can read more about Bitbucket app passwords here.
Updating your README file to show the badges
I use a README.rst
file (using the RestructuredText format), so this is how the top of my readme file looks, for a repository named my-project
in an organization name myorg
.
my-project
##########|Build-Status| |Coverage|.. |Build-Status| image:: https://bitbucket.org/myorg/my-project/downloads/status.svg
:target: https://bitbucket.org/myorg/my-project/addon/pipelines/home#!/.. |Coverage| image:: https://bitbucket.org/myorg/my-project/downloads/coverage.svg
:target: https://bitbucket.org/myorg/my-project/addon/pipelines/home#!/
If you you use markdown (as in README.md
), the following should do:
# my-project[![Build-Status](https://bitbucket.org/myorg/my-project/downloads/status.svg)](https://bitbucket.org/myorg/my-project/addon/pipelines/home#!/)
[![Coverage](https://bitbucket.org/myorg/my-project/downloads/coverage.svg)](https://bitbucket.org/myorg/my-project/addon/pipelines/home#!/)
That’s it! If anything doesn’t work read part 2 to understand more about the solution. It should help you adapt the code or configuration to make it work for you.
Part 2: Understanding how it works
The required files
The solution is made up of several parts:
bitbucket-pipelines.yml
— This is the configuration file for Bitbucket’s CI/CD component, much like Github Actions or independent ones like Travis or Circle CI. Most of the logic goes here.status_badge.sh
— A script generating the appropriate status and coverage badges. I placed this in a directory namedci
in the root of my repository.README.rst
(orREADME.md
) — Here you just reference the right urls for the generated badges.pytest.ini
or arguments you provide to thepytest
command — Not really a part of the solution, but the script assumes your testing phase generates a coverage report.
The overall structure
Since most of the work is done through the different steps configured by the bitbucket-pipelines.yml
file, let’s start by going over the file, and the short status_badge.sh
script it uses:
So the main point of this configuration is to run four pipeline steps on each commit to our master
branch:
pipelines:
default:
- <<: *test
branches:
master:
- <<: *test
- <<: *upload-status-badge
- <<: *upload-coverage-badge
- <<: *build-status
The default
part means only the test phase will run for commits to other branches, but for master
we will perform the following four steps:
- Run the
test
phase, which will run all tests AND generate appropriatestatus.svg
andcoverage.svg
files AND will save them (and the exit code returned by thepytest
command) using the Bitbucket Pipelines artifacts mechanism. - Upload the status badge to the Downloads section of your repository.
- Upload the coverage badge to the Downloads section of your repository.
- Run a step that will simply exit with the previously-stored exit value returned by
pytest
. This will make sure the build will fail ifpytest
fails, but will pass if everything goes fine.
This whole structure is the result of two technical details:
- The easiest way, at the moment, to upload Bitbucket Pipelines build artifacts to the corresponding repository’s Downloads store/section is using the official
bitbucket-upload-file
docker/step (see here for details). - Bitbucket Pipelines does not, at the moment, support running pipeline steps after a step has failed. As a result, and since upload is done by separate steps, we can’t have the
test
step — and thus thepytest
command — fail, and so we have to add a final step just to make the overall build status correspond to test results. Not very elegant, but it’s the best I could think of.
The solution I ended up with is to export an environment variable holding the exit status of the pytest
into a shared_vars.sh
file, and then use Bitbucket’s artifacts
mechanism to save both this file and the two generated svg
badges and have them carry over to future steps.
The way the shared_vars.sh
file used here to export environment variables into and source environment variables from in a later stage can be generally used for communication between Bitbucket Pipelines stages.
Dependencies & assumptions
The python code used here has several Python package dependencies:
pytest
runs the tests.coverage
andpytest-cov
produce coverage reports onpytest
runspybadges
generates the build status badge.coverage-badge
generates the coverage badge.