Refactor list outputs
Current situation
When using opentf-ctl get xxxs
, we are duplicating behaviors from resources to resources, and the format options are limited. We cannot get YAML or JSON data, which makes using opentf-ctl
in scripts harder than it should be (csv is not that expressive).
Desired outcome
We should use a generic mechanism, relying on (a subset of) jsonpath, and we should be able to get yaml or json output.
This applies to the following subcommands:
get workflows
get channels
get agents
get qualitygate
get subscriptions
It does not apply to get workflow
, for which it is not relevant.
The changes are:
Those subcommands allow for -o yaml
and -o json
in addition to -o wide
and -o custom-columns=...
(the long form --option=
is also allowed).
The yaml
and json
output give a list of objects (workflows, channels, agents, rules, or subscriptions, respectively).
The console output is no longer in CSV form. It uses fixed-width columns now.
> opentf-ctl get workflows --context allinone -o wide
WORKFLOW_ID STATUS FIRST_SEEN_TIMESTAMP NAME
caa5b611-cf9c-494f-a1ff-e291d1614bd1 FAILED 2023-07-28T09:27:10.277243 demo expressions
29e457d1-d574-40b1-af69-3a4111b60895 DONE 2023-07-28T09:29:14.789645 demo expressions
a30f6c3d-2da7-4e90-8583-a9bc8cd22de2 DONE 2023-07-28T09:30:18.189441 demo expressions
output-columns
now allow for more jsonpath-like values. Any value in the object can be queried.
The column format is as follows:
.{segment}[.{segment}]*
, where segment
is either a field name or *
or *~
.
*~
can only be used at the end. An error is raised if it is used as an intermediate segment. It returns the keys of the object.
If a segment is not found in the data, <none>
is returned.
Assuming the following object:
{
"metadata": {
"name": "my name",
"labels": {
"label_1": "value_1",
"label_2": "value_2"
}
},
"jobs": {
"job_1": {
"runs-on": ["windows", "foo"],
"steps": [
{ "run": "echo hi" },
{ "run": "echo bye" }
]
},
"job_2": {
"runs-on": ["windows", "bar"],
"steps": [
{ "run": "echo ola" },
{ "run": "echo alo" }
]
}
}
}
The following column descriptions give:
-
.metadata.name
->"my name"
-
.metadata.namespace
->"<none>"
-
.metadata.labels.*
->["value_1", "value_2"]
-
.metadata.labels.*~
->["label_1", "label_2"]
-
.jobs.*~
->["job_1", "job_2"]
-
.jobs.*.runs-on
->[["windows", "foo"], ["windows", "bar"]]
-
.jobs.*.runs-on.*
->["windows", "foo", "windows", "bar"]