A recent code-review on a new build pipeline got Sandra's attention (previously). The normally responsible and reliable developer responsible for the commit included this in their Jenkinsfile:
sh '''
if ! command -v yamllint &> /dev/null; then
if command -v apt-get &> /dev/null; then
apt-get update && apt-get install -y yamllint
elif command -v apk &> /dev/null; then
apk add --no-cache yamllint
elif command -v pip3 &> /dev/null; then
pip3 install --break-system-packages yamllint
fi
fi
find . -name '*.yaml' -exec yamllint {} \\; || true
find . -name '*.yml' -exec yamllint {} \\; || true
'''
So the goal of this script is to check to see if the yamllint
command is available. If it isn't, we check if apt-get
is available, and if it is, we use that to install yamllint
. Failing that, we try apk
, Alpine's package manager, and failing that we use pip3
to install it out of PyPI. Then we run it against any YAML files in the repo.
There are a few problems with this approach.
The first, Sandra notes, is that they don't use Alpine Linux, and thus there's no reason to try apk
. The second is that this particular repository contains no Python components and thus pip
is not available in the CI environment. Third, this CI job runs inside of a Docker image which already has yamllint
installed.
Now, you'd think the developer responsible would have known this, given that this very merge request also included the definition of the Dockerfile
for this environment. They'd already installed yamllint
in the image.
Sandra writes:
This kind of sloppiness is also wildly out of character for him, to the point where my first thought was that it was AI-generated - especially since this was far from the only WTF in the submitted Jenkinsfile. Thankfully, it didn't pass code review and was sent back for intensive rework.
Finally, while the reality is that we'll always need to resolve some dependencies at build time, things like "tooling" and "linters" really belong in the definition of the build environment, not resolved at build time.
