Static code check for a Gerrit refspec
I wanted to introduce static code check for our repo in Gerrit. Gerrit allows you to fetch the given refspec, then you may use git diff-tree to see what files are in the given change. The trouble is that you already need the repo cloned to do so, which is not that efficient for a larger repo. Fear not, the Gerrit ssh API is to the rescue. Let’s how to make it work.
Let’s say you set up a Jenkins job to be triggered from Gerrit whenever a patchset is created. Gerrit sends a bunch of parameter about the given commit to Jenkins, eg.
GERRIT_CHANGE_ID=I95e8231824c3d63d063b10c8a1d638cc42e3dd44GERRIT_CHANGE_NUMBER=40175GERRIT_PROJECT=myrepoGERRIT_REFSPEC=refs/changes/75/40175/4
ssh -p $GERRIT_PORT $GERRIT_HOST gerrit query –files –format JSON change:$GERRIT_CHANGE_NUMBER –current-patch-set | jq -r “select(.project==\”$GERRIT_PROJECT\”)|.currentPatchSet.files[].file”
/COMMIT_MSGaaa.shbbb.groovy
Now we have to filter /COMMIT_MSG, since it’s not an actual file in the commit, rather the commit message which we are not interested in this time. So we have two files in the patchset: ‘aaa.sh’ and ‘bbb.groovy’.
Once we have the affected files we use git archive to get only these specific files even from a large repo:
git archive –format=tar –remote=ssh://${GERRIT_HOST}:${GERRIT_PORT}/${GERRIT_PROJECT} “$GERRIT_REFSPEC” “${FILES[@]}” | tar xf –
The FILES array is supposed to contain “aaa.sh” and “bbb.groovy” strings. Note that I omitted the –prefix parameter, so it dumps the files to the current directory, ie. to $WORKSPACE
Finally we run a docker container to do some checks on these files:
docker run –rm -u $(id -u):$(id -g) –name “${JOB_NAME}-${BUILD_NUMBER}” -v “${WORKSPACE}:${WORKSPACE}” -w “$WORKSPACE” -e PATTERN=”.*(sh|inc|groovy)” “static_check:latest”
Notice the PATTERN variables in which we may define what file extensions we want to include in the static code check. I recommend to make this a job variable.
The actual entrypoint in the container executes the following code:
#!/bin/bash
set -o nounset
set -o errexit
set -o pipefailPATTERN=”${PATTERN:-.*(sh|inc|groovy)}”
error() {
echo “$*”
exit 1
}check_for_trailing_whitespace() {
local f=”$1″if grep ‘[[:blank:]]$’ “$f”; then
error “Trailing whitespace in the above lines”
fi
}while read -r f; do
echo “Checking ${f}”check_for_trailing_whitespace “$f”
if [[ “$f” =~ .sh$ || “$f” =~ .inc$ ]]; then
shellcheck “$f”
fi
done < <(find . -type f -regextype posix-extended -regex “$PATTERN”)
The above code check every file for trailing white characters, and runs shellcheck for each file with .sh or .inc extensions.
Leave a Reply