Newsletter
TechAnV Blog
Get updates on security engineering, Rust, eBPF, and DevSecOps. No spam, unsubscribe anytime.
Check your inbox and click the confirmation link to complete your subscription.
Auto-formatting YAML files with yamlfmt#
I decided to see if there was an equivalent of Black or Prettier for YAML files. I found yamlfmt from Google.
Update: It turns out Prettier can format YAML too.
Installation#
They suggest this:
1go install github.com/google/yamlfmt/cmd/yamlfmt@latestThis worked on my machine because I had Go installed via Homebrew (go version go1.20.4 darwin/arm64 according to go version).
I wasn’t sure where it had been installed - it turns out that if you don’t have a GOPATH environment variable set then tools installed like this default to landing in ~/go/bin.
If you don’t have Go installed, you can instead download a compiled binary from google/yamlfmt/releases.
Usage#
You can pass files to it explicitly:
1~/go/bin/yamlfmt .github/workflows/*.ymlOr you can run against every file .yml or .yaml file in a directory and its subdirectories:
1~/go/bin/yamlfmt .The default format looked like this:
1name: Publish Python Package2on:3 release:4 types: [created]5jobs:6 test:7 runs-on: ubuntu-latest8 strategy:9 matrix:10 python-version: ["3.8", "3.9", "3.10", "3.11"]11 steps:12 - uses: actions/checkout@v213 - name: Set up Python ${{ matrix.python-version }}14 uses: actions/setup-python@v215 with:16 python-version: ${{ matrix.python-version }}Configuration#
It removed some of my whitespace (I had newlines in front of those on: and jobs: keys), and I really didn’t like the way it handled lists - adding an unnecessary additional two spaces of indent before each list item.
You can pass it configuration to fix this.
Here’s what I ended up with:
1~/go/bin/yamlfmt \2 -formatter indentless_arrays=true,retain_line_breaks=true \3 .github/workflows/*.ymlThe order of this matters: you can’t put -formatter after the list of files or it will be silently ignored.
This gave me:
1name: Publish Python Package2
3on:4 release:5 types: [created]6
7jobs:8 test:9 runs-on: ubuntu-latest10 strategy:11 matrix:12 python-version: ["3.8", "3.9", "3.10", "3.11"]13 steps:14 - uses: actions/checkout@v215 - name: Set up Python ${{ matrix.python-version }}16 uses: actions/setup-python@v217 with:18 python-version: ${{ matrix.python-version }}There’s also a mechanism where you can put configuration options in a .yamlfmt file, or a file passed using --conf - those are explained here.
Configuring defaults#
You can set system-wide defaults for the tool by adding a .yamlfmt in the right place. On macOS I found it worked putting it here:
1/.config/yamlfmt/.yamlfmtI set the following options in that file:
1formatter:2 retain_line_breaks: true3 indentless_arrays: true4 scan_folded_as_literal: trueNow I can run ymalfmt anywhere without extra arguments and get my preferred formatting rules.
I added scan_folded_as_literal: true because I noticed that it was reformatting my > string literal blocks to a single line, which I didn’t like. Here’s what it was doing:
1expected: >2 Here comes a table <table>3 <thead><tr><th>One</th><th>Two</th></tr></thead>4 <tbody> <tr><td>1</td><td>2</td></tr> </tbody>5 </table> Done6 Here comes a table <table> <thead><tr><th>One</th><th>Two</th></tr></thead> <tbody> <tr><td>1</td><td>2</td></tr> </tbody> </table> DoneRunning it in CI with -lint#
The -lint option lets you check formatting in CI and fail if it would reformat (like black --check). You can run it like this:
1~/go/bin/yamlfmt \2 -formatter indentless_arrays=true,retain_line_breaks=true \3 -lint \4 .github/workflows/*.ymlWhich will output a full copy of the reformatted file, with as indicator as to which lines it changes.
I found that a bit noisy. You can add -quiet to get a less verbose output showing just the file paths that would change:
1~/go/bin/yamlfmt \2 -formatter indentless_arrays=true,retain_line_breaks=true \3 -lint \4 -quiet \5 .github/workflows/*.ymlOutput:
12023/07/13 07:16:36 The following files had formatting differences:2
3.github/workflows/publish.yml