Knowing about your ENV
variables can be really helpful. Knowing how to make
them more readable can be even more helpful. Today we are going to look at some
strategies for making env variables (and $PATH
in particular) easier to read
and easier to reason about. We’ll also touch on how to install tools like ubi
and is in GitHub CI and take a quick peek at
how using $GITHUB_STEP_SUMMARY
can provide a quality of life improvement for
those of us looking at CI logs.
As I run through various scenarios, I will use a Docker container so that we have a minimal environment. My real life environment is way messier. I won’t burden you with that, so let’s see what the Docker env looks like by default:
The Default env#
$ env
HOSTNAME=ada083235895
SHLVL=1
HOME=/root
GOTOOLCHAIN=local
TERM=xterm
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
GOPATH=/go
PWD=/workspace
GOLANG_VERSION=1.24.4
I see a couple of problems. First off, it’s hard for me to see what I want when things aren’t sorted. Let’s sort our env.
The Sorted env#
$ env | sort
GOLANG_VERSION=1.24.4
GOPATH=/go
GOTOOLCHAIN=local
HOME=/root
HOSTNAME=ada083235895
PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/workspace
SHLVL=1
TERM=xterm
This is already better, but I have to say that the PATH
is not easy to to read.
I don’t want to spend a lot of time staring at it. Can we do better? Well, we
can isolate the variable to start with.
The Split PATH#
$ echo $PATH
/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
What if we could split on the colon? That would help.
$ echo $PATH | tr : '\n'
/go/bin
/usr/local/go/bin
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
A pretty path
"Forrest H. Dutlinger Natural Area (Revisit) (2)" by Nicholas_T is licensed under CC BY 2.0 .
A Tabular env#
Fortunately we’re getting somewhere. Unfortunately I’ve now run out of
patience with shell scripting. It turns out that
is has us covered, though. Let’s see the ENV
in a tabular format.
$ is known summary var
┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┃ Name ┃ Value ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ GOLANG_VERSION ┃ 1.24.4 ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ GOPATH ┃ /go ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ GOTOOLCHAIN ┃ local ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ HOME ┃ /root ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ HOSTNAME ┃ ada083235895 ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ PATH ┃ /go/bin ┃
┃ ┃ /usr/local/go/bin ┃
┃ ┃ /usr/local/sbin ┃
┃ ┃ /usr/local/bin ┃
┃ ┃ /usr/sbin ┃
┃ ┃ /usr/bin ┃
┃ ┃ /sbin ┃
┃ ┃ /bin ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ PWD ┃ /workspace ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ SHLVL ┃ 1 ┃
┣━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━┫
┃ TERM ┃ xterm ┃
┗━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛
This feels like an improvement to me. We have a sortend ENV
with aligned
columns and our $PATH
is split on newlines, making it easier to distinguish
between similar paths like /usr/local/bin
and /usr/local/sbin
.
A JSON env#
Maybe we want do do something programmatic with ENV
or maybe the tabular
layout does not look good in our terminal logging. We do have another option:
JSON.
$ is known summary var --json
{
"GOLANG_VERSION": "1.24.4",
"GOPATH": "/go",
"GOTOOLCHAIN": "local",
"HOME": "/root",
"HOSTNAME": "ada083235895",
"PATH": [
"/go/bin",
"/usr/local/go/bin",
"/usr/local/sbin",
"/usr/local/bin",
"/usr/sbin",
"/usr/bin",
"/sbin",
"/bin"
],
"PWD": "/workspace",
"SHLVL": "1",
"TERM": "xterm"
}
Cool! Now I can get the first item in my PATH
via jq
.
$ is known summary var --json | jq .PATH[0]
"/go/bin"
Logging env in CI via Markdown#
I’d love to emit this in my CI logs so that I can get debugging info on my environment. Let’s install is into our container in GitHub Actions:
---
jobs:
linux:
runs-on: ubuntu-latest
steps:
- name: Install is
uses: oalders/install-ubi-action@v0.0.6
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
projects: oalders/is
- name: Display summaries
run: |
is known summary os --md >> $GITHUB_STEP_SUMMARY
is known summary var --md >> $GITHUB_STEP_SUMMARY
What happened?
- We used
oalders/install-ubi-action
to install ubi, which is the
“Universal Binary Installer”.
ubi
allows us to install is without needing to care about which release we need to download and install. - We installed is
- We emitted a summary for the os and for the environment variables
- The summary was added to the
$GITHUB_STEP_SUMMARY
environment variable - We used a flag which has just recently been added to
is
:--md
The --md
flag allows us to emit data in a Markdown table
format. Why would we want to do this? Well, it turns out that GitHub logs are
not always easy to read, and they can be constrained by width. So, if you have
some really long paths in your environment, tabular data becomes close to
unreadable.
GitHub offers the $GITHUB_STEP_SUMMARY
variable as a nice solution to this.
If markdown ends up in this variable, it gets rendered in an HTML summary of
that build step. This means you get way more flexibility in how the data is
rendered. There’s also the bonus that you don’t have to scroll through giant
log files to find it.
And our PATH
looks great:
Also, I can now embed the table directly into this blog post without needing to do any manual conversion to Markdown.
is known summary var --md
Name | Value |
---|---|
GOLANG_VERSION | 1.24.4 |
GOPATH | /go |
GOTOOLCHAIN | local |
HOME | /root |
HOSTNAME | 44db2d2f4c32 |
PATH | /go/bin /usr/local/go/bin /usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin |
PWD | /workspace |
SHLVL | 1 |
TERM | xterm |
So Long!#
I think I’m not quite done with adding new commands to is, but for today I’m done with writing about it. 😅