Skip to content

Commit c602937

Browse files
robbat2Codex
andauthored
feat: K8S KYAML output format support (#2560)
* feat: K8S KYAML output format support Reference: https://github.com/kubernetes/enhancements/blob/master/keps/sig-cli/5295-kyaml/README.md Co-authored-by: Codex <codex@openai.com> Generated-with: OpenAI Codex CLI (partial) Signed-off-by: Robin H. Johnson <rjohnson@coreweave.com> * build: gomodcache/gocache should not be committed Signed-off-by: Robin H. Johnson <rjohnson@coreweave.com> * chore: fix spelling of behaviour Signed-off-by: Robin H. Johnson <robbat2@gentoo.org> * build: pass GOFLAGS to docker to support buildvcs=false In trying to develop the KYAML support, various tests gave false positive results because they made assumptions about Git functionality Make it possible to avoid that by passing GOFLAGS='-buildvcs=false' to to Makefile. Signed-off-by: Robin H. Johnson <robbat2@gentoo.org> * doc: cover documentScenarios for tests Signed-off-by: Robin H. Johnson <rjohnson@coreweave.com> * build: exclude go caches from gosec Without tuning, gosec scans all of the vendor/gocache/gomodcache, taking several minutes (3m35 here), whereas the core of the yq takes only 15 seconds to scan. If we intend to remediate upstream issues in future; add a seperate target to scan those. Signed-off-by: Robin H. Johnson <rjohnson@coreweave.com> --------- Signed-off-by: Robin H. Johnson <rjohnson@coreweave.com> Signed-off-by: Robin H. Johnson <robbat2@gentoo.org> Co-authored-by: Codex <codex@openai.com>
1 parent 23abf50 commit c602937

26 files changed

+1388
-74
lines changed

.github/ISSUE_TEMPLATE/bug_report_v4.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ The command you ran:
3434
yq eval-all 'select(fileIndex==0) | .a.b.c' data1.yml data2.yml
3535
```
3636

37-
**Actual behavior**
37+
**Actual behaviour**
3838

3939
```yaml
4040
cat: meow
4141
```
4242
43-
**Expected behavior**
43+
**Expected behaviour**
4444
4545
```yaml
4646
this: should really work

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,7 @@ debian/files
6969
.vscode
7070

7171
yq3
72+
73+
# Golang
74+
.gomodcache/
75+
.gocache/

CONTRIBUTING.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,21 @@ Note: PRs with small changes (e.g. minor typos) may not be merged (see https://j
197197
make [local] test # Run in Docker container
198198
```
199199

200+
- **Problem**: Tests fail with a VCS error:
201+
```bash
202+
error obtaining VCS status: exit status 128
203+
Use -buildvcs=false to disable VCS stamping.
204+
```
205+
- **Solution**:
206+
Git security mechanisms prevent Golang from detecting the Git details inside
207+
the container; either build with the `local` option, or pass GOFLAGS to
208+
disable Golang buildvcs behaviour.
209+
```bash
210+
make local test
211+
# OR
212+
make test GOFLAGS='-buildvcs=true'
213+
```
214+
200215
### Documentation Generation Issues
201216
- **Problem**: Generated docs don't update after test changes
202217
- **Solution**:

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ clean:
3535
## prefix before other make targets to run in your local dev environment
3636
local: | quiet
3737
@$(eval ENGINERUN= )
38+
@$(eval GOFLAGS="$(GOFLAGS)" )
3839
@mkdir -p tmp
3940
@touch tmp/dev_image_id
4041
quiet: # this is silly but shuts up 'Nothing to be done for `local`'

Makefile.variables

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ IMPORT_PATH := github.com/mikefarah/${PROJECT}
44
export GIT_COMMIT = $(shell git rev-parse --short HEAD)
55
export GIT_DIRTY = $(shell test -n "$$(git status --porcelain)" && echo "+CHANGES" || true)
66
export GIT_DESCRIBE = $(shell git describe --tags --always)
7+
GOFLAGS :=
78
LDFLAGS :=
89
LDFLAGS += -X main.GitCommit=${GIT_COMMIT}${GIT_DIRTY}
910
LDFLAGS += -X main.GitDescribe=${GIT_DESCRIBE}
@@ -33,6 +34,7 @@ DEV_IMAGE := ${PROJECT}_dev
3334

3435
ENGINERUN := ${ENGINE} run --rm \
3536
-e LDFLAGS="${LDFLAGS}" \
37+
-e GOFLAGS="${GOFLAGS}" \
3638
-e GITHUB_TOKEN="${GITHUB_TOKEN}" \
3739
-v ${ROOT}/vendor:/go/src${SELINUX} \
3840
-v ${ROOT}:/${PROJECT}/src/${IMPORT_PATH}${SELINUX} \

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
![Build](https://github.com/mikefarah/yq/workflows/Build/badge.svg) ![Docker Pulls](https://img.shields.io/docker/pulls/mikefarah/yq.svg) ![Github Releases (by Release)](https://img.shields.io/github/downloads/mikefarah/yq/total.svg) ![Go Report](https://goreportcard.com/badge/github.com/mikefarah/yq) ![CodeQL](https://github.com/mikefarah/yq/workflows/CodeQL/badge.svg)
44

55

6-
A lightweight and portable command-line YAML, JSON, INI and XML processor. `yq` uses [jq](https://github.com/stedolan/jq) (a popular JSON processor) like syntax but works with yaml files as well as json, xml, ini, properties, csv and tsv. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
6+
A lightweight and portable command-line YAML, JSON, INI and XML processor. `yq` uses [jq](https://github.com/stedolan/jq) (a popular JSON processor) like syntax but works with yaml files as well as json, kyaml, xml, ini, properties, csv and tsv. It doesn't yet support everything `jq` does - but it does support the most common operations and functions, and more is being added continuously.
77

88
yq is written in Go - so you can download a dependency free binary for your platform and you are good to go! If you prefer there are a variety of package managers that can be used as well as Docker and Podman, all listed below.
99

@@ -415,7 +415,7 @@ Flags:
415415
-h, --help help for yq
416416
-I, --indent int sets indent level for output (default 2)
417417
-i, --inplace update the file in place of first file given.
418-
-p, --input-format string [auto|a|yaml|y|json|j|props|p|csv|c|tsv|t|xml|x|base64|uri|toml|hcl|h|lua|l|ini|i] parse format for input. (default "auto")
418+
-p, --input-format string [auto|a|yaml|y|json|j|kyaml|ky|props|p|csv|c|tsv|t|xml|x|base64|uri|toml|hcl|h|lua|l|ini|i] parse format for input. (default "auto")
419419
--lua-globals output keys as top-level global variables
420420
--lua-prefix string prefix (default "return ")
421421
--lua-suffix string suffix (default ";\n")
@@ -424,7 +424,7 @@ Flags:
424424
-N, --no-doc Don't print document separators (---)
425425
-0, --nul-output Use NUL char to separate values. If unwrap scalar is also set, fail if unwrapped scalar contains NUL char.
426426
-n, --null-input Don't read input, simply evaluate the expression given. Useful for creating docs from scratch.
427-
-o, --output-format string [auto|a|yaml|y|json|j|props|p|csv|c|tsv|t|xml|x|base64|uri|toml|hcl|h|shell|s|lua|l|ini|i] output format type. (default "auto")
427+
-o, --output-format string [auto|a|yaml|y|json|j|kyaml|ky|props|p|csv|c|tsv|t|xml|x|base64|uri|toml|hcl|h|shell|s|lua|l|ini|i] output format type. (default "auto")
428428
-P, --prettyPrint pretty print, shorthand for '... style = ""'
429429
--properties-array-brackets use [x] in array paths (e.g. for SpringBoot)
430430
--properties-separator string separator to use between keys and values (default " = ")

acceptance_tests/inputs-format.sh

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,37 @@ EOM
154154
assertEquals "$expected" "$X"
155155
}
156156

157+
testInputKYaml() {
158+
cat >test.kyaml <<'EOL'
159+
# leading
160+
{
161+
a: 1, # a line
162+
# head b
163+
b: 2,
164+
c: [
165+
# head d
166+
"d", # d line
167+
],
168+
}
169+
EOL
170+
171+
read -r -d '' expected <<'EOM'
172+
# leading
173+
a: 1 # a line
174+
# head b
175+
b: 2
176+
c:
177+
# head d
178+
- d # d line
179+
EOM
180+
181+
X=$(./yq e -p=kyaml -P test.kyaml)
182+
assertEquals "$expected" "$X"
183+
184+
X=$(./yq ea -p=kyaml -P test.kyaml)
185+
assertEquals "$expected" "$X"
186+
}
187+
157188

158189

159190

@@ -313,4 +344,4 @@ EOM
313344
assertEquals "$expected" "$X"
314345
}
315346

316-
source ./scripts/shunit2
347+
source ./scripts/shunit2

acceptance_tests/output-format.sh

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,55 @@ EOM
280280
assertEquals "$expected" "$X"
281281
}
282282

283+
testOutputKYaml() {
284+
cat >test.yml <<'EOL'
285+
# leading
286+
a: 1 # a line
287+
# head b
288+
b: 2
289+
c:
290+
# head d
291+
- d # d line
292+
EOL
293+
294+
read -r -d '' expected <<'EOM'
295+
# leading
296+
{
297+
a: 1, # a line
298+
# head b
299+
b: 2,
300+
c: [
301+
# head d
302+
"d", # d line
303+
],
304+
}
305+
EOM
306+
307+
X=$(./yq e --output-format=kyaml test.yml)
308+
assertEquals "$expected" "$X"
309+
310+
X=$(./yq ea --output-format=kyaml test.yml)
311+
assertEquals "$expected" "$X"
312+
}
313+
314+
testOutputKYamlShort() {
315+
cat >test.yml <<EOL
316+
a: b
317+
EOL
318+
319+
read -r -d '' expected <<'EOM'
320+
{
321+
a: "b",
322+
}
323+
EOM
324+
325+
X=$(./yq e -o=ky test.yml)
326+
assertEquals "$expected" "$X"
327+
328+
X=$(./yq ea -o=ky test.yml)
329+
assertEquals "$expected" "$X"
330+
}
331+
283332
testOutputXmComplex() {
284333
cat >test.yml <<EOL
285334
a: {b: {c: ["cat", "dog"], +@f: meow}}

agents.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Create a test file `pkg/yqlib/<format>_test.go` using the `formatScenario` patte
8383
- `scenarioType` can be `"decode"` (test decoding to YAML) or `"roundtrip"` (encode/decode preservation)
8484
- Create a helper function `test<Format>Scenario()` that switches on `scenarioType`
8585
- Create main test function `Test<Format>FormatScenarios()` that iterates over scenarios
86+
- The main test function should use `documentScenarios` to ensure testcase documentation is generated.
8687

8788
Test coverage must include:
8889
- Basic data types (scalars, arrays, objects/maps)
@@ -338,6 +339,7 @@ Create `pkg/yqlib/operator_<type>_test.go` using the `expressionScenario` patter
338339
- Include `subdescription` for longer test names
339340
- Set `expectedError` if testing error cases
340341
- Create main test function that iterates over scenarios
342+
- The main test function should use `documentScenarios` to ensure testcase documentation is generated.
341343

342344
Test coverage must include:
343345
- Basic data types and nested structures

cmd/utils.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ func configureDecoder(evaluateTogether bool) (yqlib.Decoder, error) {
166166
}
167167
yqlib.ConfiguredYamlPreferences.EvaluateTogether = evaluateTogether
168168

169+
if format.DecoderFactory == nil {
170+
return nil, fmt.Errorf("no support for %s input format", inputFormat)
171+
}
169172
yqlibDecoder := format.DecoderFactory()
170173
if yqlibDecoder == nil {
171174
return nil, fmt.Errorf("no support for %s input format", inputFormat)
@@ -197,18 +200,22 @@ func configureEncoder() (yqlib.Encoder, error) {
197200
}
198201
yqlib.ConfiguredXMLPreferences.Indent = indent
199202
yqlib.ConfiguredYamlPreferences.Indent = indent
203+
yqlib.ConfiguredKYamlPreferences.Indent = indent
200204
yqlib.ConfiguredJSONPreferences.Indent = indent
201205

202206
yqlib.ConfiguredYamlPreferences.UnwrapScalar = unwrapScalar
207+
yqlib.ConfiguredKYamlPreferences.UnwrapScalar = unwrapScalar
203208
yqlib.ConfiguredPropertiesPreferences.UnwrapScalar = unwrapScalar
204209
yqlib.ConfiguredJSONPreferences.UnwrapScalar = unwrapScalar
205210

206211
yqlib.ConfiguredYamlPreferences.ColorsEnabled = colorsEnabled
212+
yqlib.ConfiguredKYamlPreferences.ColorsEnabled = colorsEnabled
207213
yqlib.ConfiguredJSONPreferences.ColorsEnabled = colorsEnabled
208214
yqlib.ConfiguredHclPreferences.ColorsEnabled = colorsEnabled
209215
yqlib.ConfiguredTomlPreferences.ColorsEnabled = colorsEnabled
210216

211217
yqlib.ConfiguredYamlPreferences.PrintDocSeparators = !noDocSeparators
218+
yqlib.ConfiguredKYamlPreferences.PrintDocSeparators = !noDocSeparators
212219

213220
encoder := yqlibOutputFormat.EncoderFactory()
214221

0 commit comments

Comments
 (0)