Woodpecker CI & Alpine Linux ash
I recently started setting up a new CI/CD environment in my homelab (due to reasons), and this time I decided to test Woodpecker CI1. It was quite easy to setup, even with both server and agents running in Kubernetes, but I ran into some silly but confusing issues when dealing with environment variables in an Alpine Linux based build step.
TL;DR for alpine linux/ash, use the older format ($FOO_BAR) for
any local environment variable, but use recommended format
(${FOO_BAR}) for any of the built-in environment variables!
The underlying issue (aside from me being slow) is that ash is not
bash, and behaves slightly different with variables than I’m used
to. Combine this with Woodpecker that tries to protect you from
accidentally exposing secrets and you get some initially confusing
string substitutions!
steps:
- name: version
image: alpine:latest
commands:
- apk add -q --no-cache curl jq py3-semver
- versions=$(curl -s -u "${CI_REPO_OWNER}:$REPO_PASS" "${CI_FORGE_URL}/api/v1/packages/${CI_REPO_OWNER}?q=$PKG_NAME")
- # do more stuff
environment:
REPO_PASS:
from_secret: foobar
PKG_NAME: "baz"
Notice how some variables are escaped like recommended in bash
(${CI_REPO_OWNER}) while some are not ($REPO_PASS). If you try to
use the same, correct format for environment variables for the step
(REPO_PASS, PKG_NAME) in question, it is just replaced by an empty
string.
This was…confusing. It seems that any of the built-in environment
variables are successfully replaced, while any variable that
comes from the workflow itself are not! Had I used bash this probably
would have worked like in the documentation, but ash is a very
minimal shell.
Beyond that, I like woodpecker so far and will use it for CI/CD in my homelab for now.
I really started with Drone CI but was confused why all examples were from 2020 and not much after. Then I discovered that Woodpecker CI is a community fork, and that everyone else seems to have moved from Drone to Woodpecker. ↩︎