monotux.tech

Woodpecker CI & Alpine Linux ash

CI/CD Woodpecker Alpine Linux

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.


  1. 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. ↩︎