Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

noyafmt + noyavalidate recipes

Common workflows. Each recipe is a self-contained snippet you can drop into your project or CI.

CI: format gate

Block PRs that introduce unformatted YAML.

GitHub Actions

# .github/workflows/yaml-fmt.yml
name: YAML format
on: [pull_request]
jobs:
  fmt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cargo install noya-cli --locked
      - run: noyafmt --check $(git ls-files '*.yaml' '*.yml')

GitLab CI

yaml-fmt:
  image: rust:1.89-bookworm
  before_script:
    - cargo install noya-cli --locked
  script:
    - noyafmt --check $(git ls-files '*.yaml' '*.yml')

Pre-commit hook

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: noyafmt
        name: noyafmt --check
        entry: noyafmt --check
        language: system
        files: \.(yaml|yml)$

CI: schema gate

Block PRs that violate a JSON Schema contract.

GitHub Actions

name: YAML schema
on: [pull_request]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: cargo install noya-cli --locked
      - name: Validate Kubernetes manifests
        run: |
          for f in k8s/**/*.yaml; do
            noyavalidate --schema schemas/k8s.schema.yaml "$f" || exit 1
          done

Editor integration

VS Code on save

Pair noyafmt with VS Code’s editor.formatOnSave. The recommended path is the dedicated noyalib-lsp extension, which provides format-on-save, diagnostics, and hover. For lighter-weight integration:

// .vscode/tasks.json
{
  "version": "2.0.0",
  "tasks": [{
    "label": "noyafmt: write",
    "type": "shell",
    "command": "noyafmt",
    "args": ["--write", "${file}"],
    "problemMatcher": []
  }]
}

Neovim

-- ~/.config/nvim/lua/yaml-fmt.lua
vim.api.nvim_create_autocmd("BufWritePost", {
  pattern = { "*.yaml", "*.yml" },
  callback = function()
    vim.fn.system("noyafmt --write " .. vim.fn.expand("%"))
    vim.cmd("e!") -- reload buffer
  end,
})

For the richer experience (diagnostics, hover, code actions) use noyalib-lsp via nvim-lspconfig.

Bulk operations

Format every YAML in a tree

find . -name '*.yaml' -o -name '*.yml' | xargs noyafmt --write

Validate every Kubernetes manifest

find k8s -name '*.yaml' -exec \
  noyavalidate --schema schemas/k8s.schema.yaml --quiet {} +

Generate canonical diff after a refactor

When mass-renaming keys across many YAML files, format both before and after to reduce the diff to the actual semantic change:

git stash                                            # save WIP
noyafmt --write **/*.yaml && git commit -m 'fmt'     # format baseline
git stash pop                                        # apply WIP
noyafmt --write **/*.yaml                            # format after
git diff                                             # only semantic changes

Pipeline integration

kubectl apply only when format-clean

noyafmt --check k8s.yaml && kubectl apply -f k8s.yaml

Helm chart linting

helm template ./chart \
  | noyavalidate --schema schemas/k8s.schema.yaml -

Render-then-validate Argo CD application

argocd app manifests my-app \
  | noyavalidate --schema schemas/argo-app.schema.yaml -

Troubleshooting

“permission denied” rewriting a file

--write opens FILE for writing. If the file is read-only or owned by another user, the write fails with exit 3 (I/O error). Use chmod +w FILE or sudo.

Schema validation passes locally, fails in CI

The schema file path is resolved relative to the working directory of the noyavalidate invocation, not relative to the input file. In GitHub Actions, ${{ github.workspace }} is the repo root; ensure your --schema path is relative to that.

--fix changed more than I expected

The CST formatter normalises whitespace, quoting, and indentation to a canonical form. It does not change document semantics: keys, values, comments, anchors, and tags survive byte-for-byte. If a --fix produced unexpected output, file an issue with the input — the formatter is documented as preserving everything that isn’t trivia.

Stdin closes the process before output

When piping --stdin you may need to terminate the input with Ctrl-D (^D) on a new line:

noyafmt --stdin
key: value
^D

For programmatic use (CI scripts), redirect a file or use <<< heredoc syntax.