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 workflowsget channelsget agentsget qualitygateget 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"]