Provide documentation on how to integrate diff_cover with Gitlab/Github projects
Hi, I found some troubles integrating diff_cover in my CI/CD pipeline and I would like to share how I did get it to work. My project is hosted on Gitlab but I use Teamcity for its CI/CD (rather than the .gitlab-ci.yaml file). I think however the "problems" I hit might be similar in other use cases.
Here are the 2 issues I found:
- when Teamcity is doing the checkout of the project to build it, it does not fetch all the git references, just a minimal subset. To make an example: if Teamcity is building the branch "feature/xyz" it will instruct git to fetch from the repo only that reference and will not fetch things like "develop" or "master" refs. This is no-go with diff_cover since I wanted to run diff_cover on every merge/pull request of feature branches against the "develop" branch of my project. Here is the code I developed (in my GNU make Makefile) to work around the problem:
# diff-cover utility works by running a "git diff origin/develop..HEAD" command and then cross-checking the
# data in the Cobertura XML file with the data out of the "git diff" operation.
# The problem here is that Teamcity and several other CI servers will not checkout all the branches of the project to build,
# only a strictly required subset of "refs". This makes the git diff step fail with an error like:
# diff_cover.command_runner.CommandError: fatal: ambiguous argument 'origin/develop...HEAD': unknown revision or path not in the working tree.
# To workaround the problem here we force the build agent to fetch all references in the remote repository, including "origin/develop".
# To do that we need however to have gitlab credentials available and provide them in a non-interactive way to git fetch command,
# see https://stackoverflow.com/questions/8536732/can-i-hold-git-credentials-in-environment-variables/43022442#43022442
@echo '#!/bin/bash' > /tmp/diff-cover-git-credential-helper.sh
@echo "sleep 1" >> /tmp/diff-cover-git-credential-helper.sh
@echo "echo username=$$GITLAB_USER" >> /tmp/diff-cover-git-credential-helper.sh
@echo "echo password=$$GITLAB_ACCESS_TOKEN" >> /tmp/diff-cover-git-credential-helper.sh
#@echo "BEFORE FETCH"
#@git show-ref
@echo "Now fetching all git references from remote Gitlab repository"
@git -c credential.helper="/bin/bash /tmp/diff-cover-git-credential-helper.sh" fetch
#@echo "AFTER FETCH"
#@git show-ref
@rm -f /tmp/diff-cover-git-credential-helper.sh
- I wanted to have diff_cover results readily available directly inside each gitlab MR. This facilitates the maintenance tasks for maintainers. A possibility for doing that would be writing a Gitlab/github bot that takes each PR/MR , runs diff_cover on them and then creates a comment entry in the PR/MR itself. However I found it easier in my case to just invoke gitlab rest API to create a comment directly inside my pipeline. Here's the code I developed (again in GNU make Makefile format):
@echo "Creating message to post in Gitlab as temporary file /tmp/diff-cover-comment.json"
@jq -Rs <$(TEAMCITY_ARTIFACTS_DIR_COVERAGE_HTML_REPORT)/diff-coverage.txt >/tmp/diff-cover-tmp.json
@echo '{ "body": "" }' | jq --slurpfile texts /tmp/diff-cover-tmp.json '.body=$$texts[0]' >/tmp/diff-cover-comment.json
@echo "Now adding a comment to the associated MR number $(TC_PULLREQUEST_NUMBER) in gitlab with the results of diff-cover."
curl --include --show-error --request POST \
--header "Private-Token: $(GITLAB_ACCESS_TOKEN)" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "@/tmp/diff-cover-comment.json" \
https://gitlab.com/api/v4/projects/$(GITLAB_PROJECT_ID)/merge_requests/$(TC_PULLREQUEST_NUMBER)/notes || true
It assumes that the results of diff_cover are available (in Markdown format!!) inside the file $(TEAMCITY_ARTIFACTS_DIR_COVERAGE_HTML_REPORT)/diff-coverage.txt . It also assumes that there are environment variables like GITLAB_ACCESS_TOKEN and GITLAB_PROJECT_ID and TC_PULLREQUEST_NUMBER that provide all the data required to invoke the rest API.
I think these 2 "problems"/issues I hit are something that might benefit others so I wonder if a) there are better solutions compared to my 2 solutions above that you are aware of b) is there anything that could be added into diff_cover to provide these solutions out-of-the-box (I doubt) c) it makes sense to document these steps
Thanks