Skip to content

Commit 6dc3a4d

Browse files
authored
🤖 fix: make generated CRD API docs YAML-oriented (#59)
Summary Improves generated CRD API reference docs so they read more like YAML users actually write, with cleaner field/type names and selective nested-object expansion for actionable object fields. Background The generated docs were hard to use because table keys repeated `spec.`/`status.`, type names included noisy fully-qualified package paths, and object-like fields (for example `LocalObjectReference`) did not show nested members users need in YAML. Implementation - Updated `hack/crd-ref-docs/templates/markdown/gv_list.tpl`: - removed redundant `spec.` / `status.` prefixes from table rows. - shortened common type package paths (`metav1`, `corev1`, and local API types). - added a recursive `renderFields` template for nested field expansion. - constrained expansion to project-local API types and `corev1.LocalObjectReference` with depth limit 3 to avoid doc bloat. - Regenerated API reference outputs under `docs/reference/api/*.md`. Validation - `make verify-vendor` - `make test` - `make build` - `make lint` - `make docs-reference` - `make docs-check` Risks Low to moderate. This changes only documentation generation templates and generated markdown output, not runtime behavior. Main risk is doc rendering regressions; mitigated by successful `make docs-check` (strict mkdocs build) and regeneration checks. --- <details> <summary>📋 Implementation Plan</summary> # Plan: Make CRD API reference docs read like YAML (nested + less verbose) ## Context / Why The current generated API reference docs (e.g. `docs/reference/api/coderprovisioner.md`) are hard for users to act on: - The **Field** column repeats `spec.` / `status.` even though the table is already under `## Spec` / `## Status`. - The **Type** column shows **fully-qualified Go package paths**, which is noisy. - Most importantly, **nested struct types are opaque** (e.g. `controlPlaneRef` is a `corev1.LocalObjectReference`, but the docs don’t show that the YAML must contain `name:`). Users don’t know what to write. Goal: adjust the `crd-ref-docs` markdown template so the output is: - easier to scan, - closer to the YAML structure people actually write, - and provides actionable detail for “object” fields (at least for the important/commonly-confusing ones like `LocalObjectReference`). ## Evidence (what we verified) - API reference docs are generated by `crd-ref-docs` via `hack/update-reference-docs.sh` / `make docs-reference`. (`hack/update-reference-docs.sh`, `hack/crd-ref-docs/config.yaml`) - Output is a simple flat table produced by `hack/crd-ref-docs/templates/markdown/gv_list.tpl`. - The example in the screenshot matches `docs/reference/api/coderprovisioner.md`. - `crd-ref-docs` represents nested types via `types.Type` with a `Members()` method that returns struct fields even through aliases/slices/pointers. (`vendor/github.com/elastic/crd-ref-docs/types/types.go`) ## Implementation details ### 1) Remove redundant `spec.` / `status.` prefixes **File:** `hack/crd-ref-docs/templates/markdown/gv_list.tpl` - Change the rows under `## Spec` from: ```go-template | `spec.{{ $member.Name }}` | ... | ``` to: ```go-template | `{{ $member.Name }}` | ... | ``` - Change the rows under `## Status` from: ```go-template | `status.{{ $member.Name }}` | ... | ``` to: ```go-template | `{{ $member.Name }}` | ... | ``` **Result:** tables read like the YAML keys a user will set under `spec:` / `status:`. --- ### 2) Bonus: Clean up verbose Go type paths in the `Type` column **File:** `hack/crd-ref-docs/templates/markdown/gv_list.tpl` (the `typeName` helper) Update `typeName` to replace noisy package paths with common aliases / short names. Proposed replacements (minimal, focused on what we see in our CRDs): - `k8s.io/apimachinery/pkg/apis/meta/v1.` → `metav1.` (already present) - `k8s.io/api/core/v1.` → `corev1.` - `github.com/coder/coder-k8s/api/v1alpha1.` → `` (strip to just the type name) Shape: ```go-template {{- $typeString := $fieldType.String -}} {{- $typeString = trimPrefix "*" $typeString -}} {{- $typeString = $typeString | replace "k8s.io/apimachinery/pkg/apis/meta/v1." "metav1." -}} {{- $typeString = $typeString | replace "k8s.io/api/core/v1." "corev1." -}} {{- $typeString = $typeString | replace "github.com/coder/coder-k8s/api/v1alpha1." "" -}} {{- $typeString -}} ``` **Result:** types become readable (`corev1.LocalObjectReference`, `CoderProvisionerKeySpec`, etc.) without losing meaning. --- ### 3) Show nested fields for selected “object” types (so users know what to write) **File:** `hack/crd-ref-docs/templates/markdown/gv_list.tpl` Replace the flat `range $specMembers` / `range $statusMembers` rendering with a small recursive renderer that can optionally expand struct members. #### 3.1) Expansion policy (avoid doc bloat) We should not blindly expand every imported Kubernetes type (e.g. `corev1.EnvVar` can recursively explode). Instead, expand only when: - The field’s type has members (`len $t.Members > 0`), and - The type is either: - **Project-local** (`$t.Package` starts with `github.com/coder/coder-k8s/api/`), or - A small, commonly-confusing external wrapper like **`k8s.io/api/core/v1.LocalObjectReference`**. Add a simple depth limit (e.g. `maxDepth := 3`) to prevent runaway recursion. #### 3.2) Table rendering shape Add a new template block (name is flexible) that prints rows for a list of fields and can recurse: ```go-template {{- define "renderFields" -}} {{- $fields := index . 0 -}} {{- $depth := index . 1 -}} {{- $maxDepth := index . 2 -}} {{- $indent := repeat $depth "&nbsp;&nbsp;" -}} {{- range $f := $fields }} {{- if not $f.Type -}} {{ fail (printf "field %q is missing type information" $f.Name) }} {{- end -}} {{- $t := $f.Type -}} {{- $hasMembers := gt (len $t.Members) 0 -}} {{- $isProjectLocal := hasPrefix $t.Package "github.com/coder/coder-k8s/api/" -}} {{- $isLocalObjectRef := and (eq $t.Package "k8s.io/api/core/v1") (eq $t.Name "LocalObjectReference") -}} {{- $shouldExpand := and $hasMembers (lt $depth $maxDepth) (or $isProjectLocal $isLocalObjectRef) -}} | {{ $indent }}`{{ $f.Name }}` | `{{ template "typeName" $t }}` | {{ markdownRenderFieldDoc $f.Doc }} | {{- if $shouldExpand }} {{- template "renderFields" (list $t.Members (add $depth 1) $maxDepth) -}} {{- end }} {{- end }} {{- end -}} ``` Then render spec/status like: ```go-template ## Spec | Field | Type | Description | | --- | --- | --- | {{- template "renderFields" (list $specMembers 0 3) }} ## Status | Field | Type | Description | | --- | --- | --- | {{- template "renderFields" (list $statusMembers 0 3) }} ``` **Result:** users will see `controlPlaneRef` → `name` (and other small structs) directly in the table, without needing to understand Go types. <details> <summary>Why this policy (and not “expand everything”)?</summary> Expanding every imported Kubernetes type tends to create huge, hard-to-navigate pages and slows review. The hybrid approach targets the worst UX offenders (object refs and project-local structs) while keeping common K8s “implementation detail” structs as a single row. Follow-up options if we want more detail later: - allowlist additional external types (e.g. `metav1.LabelSelector`), - add per-type `<details>` blocks instead of in-table recursion, - or render linked “Type sections” further down the page. </details> --- ### 4) Regenerate reference docs and confirm output After template changes, regenerate docs so the repo reflects the new format. - Run: `make docs-reference` (or `bash hack/update-reference-docs.sh`) - Confirm: - `docs/reference/api/coderprovisioner.md` no longer has `spec.` / `status.` prefixes. - `controlPlaneRef` expands to show `name`. - Type strings are shortened as expected. - `mkdocs.yml` nav updates (if the script touches it). ## Validation - `make docs-reference` (ensures generator + templates work and output is updated) - `make docs-check` (ensures the docs site still builds) - (Optional but recommended) `make test` (sanity check; should be unchanged but cheap to verify) </details> --- _Generated with `mux` • Model: `openai:gpt-5.3-codex` • Thinking: `xhigh` • Cost: $0.53_ <!-- mux-attribution: model=openai:gpt-5.3-codex thinking=xhigh costs=0.53 -->
1 parent be6654a commit 6dc3a4d

7 files changed

Lines changed: 143 additions & 88 deletions

File tree

.cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"javascripts",
3232
"kubeconfig",
3333
"kubebuilder",
34+
"corev",
3435
"metav",
3536
"mkdocs",
3637
"pymdownx",

docs/reference/api/codercontrolplane.md

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,33 @@
1313

1414
| Field | Type | Description |
1515
| --- | --- | --- |
16-
| `spec.image` | `string` | Image is the container image used for the Coder control plane pod. |
17-
| `spec.replicas` | `int32` | Replicas is the desired number of control plane pods. |
18-
| `spec.service` | `github.com/coder/coder-k8s/api/v1alpha1.ServiceSpec` | Service controls the service created in front of the control plane. |
19-
| `spec.extraArgs` | `[]string` | ExtraArgs are appended to the default Coder server arguments. |
20-
| `spec.extraEnv` | `[]k8s.io/api/core/v1.EnvVar` | ExtraEnv are injected into the Coder control plane container. |
21-
| `spec.imagePullSecrets` | `[]k8s.io/api/core/v1.LocalObjectReference` | ImagePullSecrets are used by the pod to pull private images. |
22-
| `spec.operatorAccess` | `github.com/coder/coder-k8s/api/v1alpha1.OperatorAccessSpec` | OperatorAccess configures bootstrap API access to the coderd instance. |
16+
| `image` | `string` | Image is the container image used for the Coder control plane pod. |
17+
| `replicas` | `int32` | Replicas is the desired number of control plane pods. |
18+
| `service` | `ServiceSpec` | Service controls the service created in front of the control plane. |
19+
| &nbsp;&nbsp;`type` | `corev1.ServiceType` | Type controls the Kubernetes service type. |
20+
| &nbsp;&nbsp;`port` | `int32` | Port controls the exposed service port. |
21+
| &nbsp;&nbsp;`annotations` | `map[string]string` | Annotations are applied to the reconciled service object. |
22+
| `extraArgs` | `[]string` | ExtraArgs are appended to the default Coder server arguments. |
23+
| `extraEnv` | `[]corev1.EnvVar` | ExtraEnv are injected into the Coder control plane container. |
24+
| `imagePullSecrets` | `[]corev1.LocalObjectReference` | ImagePullSecrets are used by the pod to pull private images. |
25+
| &nbsp;&nbsp;`name` | `string` | Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: [https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names) |
26+
| `operatorAccess` | `OperatorAccessSpec` | OperatorAccess configures bootstrap API access to the coderd instance. |
27+
| &nbsp;&nbsp;`disabled` | `bool` | Disabled turns off creation and management of the `coder-k8s-operator` user and API token. |
28+
| &nbsp;&nbsp;`generatedTokenSecretName` | `string` | GeneratedTokenSecretName stores the generated operator API token. |
2329

2430
## Status
2531

2632
| Field | Type | Description |
2733
| --- | --- | --- |
28-
| `status.observedGeneration` | `int64` | ObservedGeneration tracks the spec generation this status reflects. |
29-
| `status.readyReplicas` | `int32` | ReadyReplicas is the number of ready pods observed in the deployment. |
30-
| `status.url` | `string` | URL is the in-cluster URL for the control plane service. |
31-
| `status.operatorTokenSecretRef` | `github.com/coder/coder-k8s/api/v1alpha1.SecretKeySelector` | OperatorTokenSecretRef points to the Secret key containing the `coder-k8s-operator` API token. |
32-
| `status.operatorAccessReady` | `bool` | OperatorAccessReady reports whether operator API access bootstrap succeeded. |
33-
| `status.phase` | `string` | Phase is a high-level readiness indicator. |
34-
| `status.conditions` | `[]metav1.Condition` | Conditions are Kubernetes-standard conditions for this resource. |
34+
| `observedGeneration` | `int64` | ObservedGeneration tracks the spec generation this status reflects. |
35+
| `readyReplicas` | `int32` | ReadyReplicas is the number of ready pods observed in the deployment. |
36+
| `url` | `string` | URL is the in-cluster URL for the control plane service. |
37+
| `operatorTokenSecretRef` | `SecretKeySelector` | OperatorTokenSecretRef points to the Secret key containing the `coder-k8s-operator` API token. |
38+
| &nbsp;&nbsp;`name` | `string` | Name is the Kubernetes Secret name. |
39+
| &nbsp;&nbsp;`key` | `string` | Key is the key inside the Secret data map. |
40+
| `operatorAccessReady` | `bool` | OperatorAccessReady reports whether operator API access bootstrap succeeded. |
41+
| `phase` | `string` | Phase is a high-level readiness indicator. |
42+
| `conditions` | `[]metav1.Condition` | Conditions are Kubernetes-standard conditions for this resource. |
3543

3644
## Source
3745

docs/reference/api/coderprovisioner.md

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,35 +13,45 @@
1313

1414
| Field | Type | Description |
1515
| --- | --- | --- |
16-
| `spec.controlPlaneRef` | `k8s.io/api/core/v1.LocalObjectReference` | ControlPlaneRef identifies which CoderControlPlane instance to join. |
17-
| `spec.organizationName` | `string` | OrganizationName is the Coder organization. Defaults to "default". |
18-
| `spec.bootstrap` | `github.com/coder/coder-k8s/api/v1alpha1.CoderProvisionerBootstrapSpec` | Bootstrap configures credentials for provisioner key management. |
19-
| `spec.key` | `github.com/coder/coder-k8s/api/v1alpha1.CoderProvisionerKeySpec` | Key configures provisioner key naming and secret storage. |
20-
| `spec.replicas` | `int32` | Replicas is the desired number of provisioner pods. |
21-
| `spec.tags` | `map[string]string` | Tags are attached to the provisioner key for job routing. |
22-
| `spec.image` | `string` | Image is the container image. Defaults to the control plane image. |
23-
| `spec.extraArgs` | `[]string` | ExtraArgs are appended after "provisionerd start". |
24-
| `spec.extraEnv` | `[]k8s.io/api/core/v1.EnvVar` | ExtraEnv are injected into the provisioner container. |
25-
| `spec.resources` | `k8s.io/api/core/v1.ResourceRequirements` | Resources for the provisioner container. |
26-
| `spec.imagePullSecrets` | `[]k8s.io/api/core/v1.LocalObjectReference` | ImagePullSecrets are used by the pod to pull private images. |
27-
| `spec.terminationGracePeriodSeconds` | `int64` | TerminationGracePeriodSeconds for the provisioner pods. |
16+
| `controlPlaneRef` | `corev1.LocalObjectReference` | ControlPlaneRef identifies which CoderControlPlane instance to join. |
17+
| &nbsp;&nbsp;`name` | `string` | Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: [https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names) |
18+
| `organizationName` | `string` | OrganizationName is the Coder organization. Defaults to "default". |
19+
| `bootstrap` | `CoderProvisionerBootstrapSpec` | Bootstrap configures credentials for provisioner key management. |
20+
| &nbsp;&nbsp;`credentialsSecretRef` | `SecretKeySelector` | CredentialsSecretRef points to a Secret containing a Coder session token with permission to manage provisioner keys. |
21+
| &nbsp;&nbsp;&nbsp;&nbsp;`name` | `string` | Name is the Kubernetes Secret name. |
22+
| &nbsp;&nbsp;&nbsp;&nbsp;`key` | `string` | Key is the key inside the Secret data map. |
23+
| `key` | `CoderProvisionerKeySpec` | Key configures provisioner key naming and secret storage. |
24+
| &nbsp;&nbsp;`name` | `string` | Name is the provisioner key name in coderd. Defaults to the CR name. |
25+
| &nbsp;&nbsp;`secretName` | `string` | SecretName is the Kubernetes Secret to store the key. Defaults to "\{crName\}-provisioner-key". |
26+
| &nbsp;&nbsp;`secretKey` | `string` | SecretKey is the data key in the Secret. Defaults to "key". |
27+
| `replicas` | `int32` | Replicas is the desired number of provisioner pods. |
28+
| `tags` | `map[string]string` | Tags are attached to the provisioner key for job routing. |
29+
| `image` | `string` | Image is the container image. Defaults to the control plane image. |
30+
| `extraArgs` | `[]string` | ExtraArgs are appended after "provisionerd start". |
31+
| `extraEnv` | `[]corev1.EnvVar` | ExtraEnv are injected into the provisioner container. |
32+
| `resources` | `corev1.ResourceRequirements` | Resources for the provisioner container. |
33+
| `imagePullSecrets` | `[]corev1.LocalObjectReference` | ImagePullSecrets are used by the pod to pull private images. |
34+
| &nbsp;&nbsp;`name` | `string` | Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: [https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names) |
35+
| `terminationGracePeriodSeconds` | `int64` | TerminationGracePeriodSeconds for the provisioner pods. |
2836

2937
## Status
3038

3139
| Field | Type | Description |
3240
| --- | --- | --- |
33-
| `status.observedGeneration` | `int64` | ObservedGeneration tracks the spec generation this status reflects. |
34-
| `status.readyReplicas` | `int32` | ReadyReplicas is the number of ready pods observed in the deployment. |
35-
| `status.phase` | `string` | Phase is a high-level readiness indicator. |
36-
| `status.conditions` | `[]metav1.Condition` | Conditions are Kubernetes-standard conditions for this resource. |
37-
| `status.organizationID` | `string` | OrganizationID is the organization ID last applied to the provisioner key. |
38-
| `status.organizationName` | `string` | OrganizationName is the organization name last applied to the provisioner key. |
39-
| `status.provisionerKeyID` | `string` | ProvisionerKeyID is the provisioner key ID last applied in coderd. |
40-
| `status.provisionerKeyName` | `string` | ProvisionerKeyName is the provisioner key name last applied in coderd. |
41-
| `status.tagsHash` | `string` | TagsHash is a deterministic hash of spec.tags last applied to the provisioner key. |
42-
| `status.controlPlaneRefName` | `string` | ControlPlaneRefName is the control plane ref name last applied to the provisioner key. |
43-
| `status.controlPlaneURL` | `string` | ControlPlaneURL is the control plane URL last applied to the provisioner key. |
44-
| `status.secretRef` | `github.com/coder/coder-k8s/api/v1alpha1.SecretKeySelector` | SecretRef references the provisioner key secret data currently in use. |
41+
| `observedGeneration` | `int64` | ObservedGeneration tracks the spec generation this status reflects. |
42+
| `readyReplicas` | `int32` | ReadyReplicas is the number of ready pods observed in the deployment. |
43+
| `phase` | `string` | Phase is a high-level readiness indicator. |
44+
| `conditions` | `[]metav1.Condition` | Conditions are Kubernetes-standard conditions for this resource. |
45+
| `organizationID` | `string` | OrganizationID is the organization ID last applied to the provisioner key. |
46+
| `organizationName` | `string` | OrganizationName is the organization name last applied to the provisioner key. |
47+
| `provisionerKeyID` | `string` | ProvisionerKeyID is the provisioner key ID last applied in coderd. |
48+
| `provisionerKeyName` | `string` | ProvisionerKeyName is the provisioner key name last applied in coderd. |
49+
| `tagsHash` | `string` | TagsHash is a deterministic hash of spec.tags last applied to the provisioner key. |
50+
| `controlPlaneRefName` | `string` | ControlPlaneRefName is the control plane ref name last applied to the provisioner key. |
51+
| `controlPlaneURL` | `string` | ControlPlaneURL is the control plane URL last applied to the provisioner key. |
52+
| `secretRef` | `SecretKeySelector` | SecretRef references the provisioner key secret data currently in use. |
53+
| &nbsp;&nbsp;`name` | `string` | Name is the Kubernetes Secret name. |
54+
| &nbsp;&nbsp;`key` | `string` | Key is the key inside the Secret data map. |
4555

4656
## Source
4757

docs/reference/api/codertemplate.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,23 @@
1313

1414
| Field | Type | Description |
1515
| --- | --- | --- |
16-
| `spec.organization` | `string` | Organization is the Coder organization name (must match the organization prefix in metadata.name). |
17-
| `spec.versionID` | `string` | VersionID is the Coder template version UUID used on creation (required for CREATE). |
18-
| `spec.displayName` | `string` | |
19-
| `spec.description` | `string` | |
20-
| `spec.icon` | `string` | |
21-
| `spec.running` | `bool` | Running is a legacy flag retained temporarily for in-repo callers that still read template run-state directly. |
16+
| `organization` | `string` | Organization is the Coder organization name (must match the organization prefix in metadata.name). |
17+
| `versionID` | `string` | VersionID is the Coder template version UUID used on creation (required for CREATE). |
18+
| `displayName` | `string` | |
19+
| `description` | `string` | |
20+
| `icon` | `string` | |
21+
| `running` | `bool` | Running is a legacy flag retained temporarily for in-repo callers that still read template run-state directly. |
2222

2323
## Status
2424

2525
| Field | Type | Description |
2626
| --- | --- | --- |
27-
| `status.id` | `string` | |
28-
| `status.organizationName` | `string` | |
29-
| `status.activeVersionID` | `string` | |
30-
| `status.deprecated` | `bool` | |
31-
| `status.updatedAt` | `metav1.Time` | |
32-
| `status.autoShutdown` | `metav1.Time` | AutoShutdown is a legacy timestamp retained temporarily for in-repo callers that still surface template shutdown timestamps. |
27+
| `id` | `string` | |
28+
| `organizationName` | `string` | |
29+
| `activeVersionID` | `string` | |
30+
| `deprecated` | `bool` | |
31+
| `updatedAt` | `metav1.Time` | |
32+
| `autoShutdown` | `metav1.Time` | AutoShutdown is a legacy timestamp retained temporarily for in-repo callers that still surface template shutdown timestamps. |
3333

3434
## Source
3535

docs/reference/api/coderworkspace.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,25 @@
1313

1414
| Field | Type | Description |
1515
| --- | --- | --- |
16-
| `spec.organization` | `string` | Organization is the Coder organization name. |
17-
| `spec.templateName` | `string` | TemplateName resolves via TemplateByName(organization, templateName). |
18-
| `spec.templateVersionID` | `string` | TemplateVersionID optionally pins to a specific template version. |
19-
| `spec.running` | `bool` | Running drives start/stop via CreateWorkspaceBuild. |
20-
| `spec.ttlMillis` | `int64` | |
21-
| `spec.autostartSchedule` | `string` | |
16+
| `organization` | `string` | Organization is the Coder organization name. |
17+
| `templateName` | `string` | TemplateName resolves via TemplateByName(organization, templateName). |
18+
| `templateVersionID` | `string` | TemplateVersionID optionally pins to a specific template version. |
19+
| `running` | `bool` | Running drives start/stop via CreateWorkspaceBuild. |
20+
| `ttlMillis` | `int64` | |
21+
| `autostartSchedule` | `string` | |
2222

2323
## Status
2424

2525
| Field | Type | Description |
2626
| --- | --- | --- |
27-
| `status.id` | `string` | |
28-
| `status.ownerName` | `string` | |
29-
| `status.organizationName` | `string` | |
30-
| `status.templateName` | `string` | |
31-
| `status.latestBuildID` | `string` | |
32-
| `status.latestBuildStatus` | `string` | |
33-
| `status.autoShutdown` | `metav1.Time` | |
34-
| `status.lastUsedAt` | `metav1.Time` | |
27+
| `id` | `string` | |
28+
| `ownerName` | `string` | |
29+
| `organizationName` | `string` | |
30+
| `templateName` | `string` | |
31+
| `latestBuildID` | `string` | |
32+
| `latestBuildStatus` | `string` | |
33+
| `autoShutdown` | `metav1.Time` | |
34+
| `lastUsedAt` | `metav1.Time` | |
3535

3636
## Source
3737

0 commit comments

Comments
 (0)