Skip to content

Commit

Permalink
support field custom documentation strings (#394)
Browse files Browse the repository at this point in the history
Adds support for extending the documentation strings for fields and
setting docstrings for custom fields.

A new `FieldConfig.Documentation` configuration option is now supported.
When present, this string *extends* any documentation provided for the
existing field by the doc-2.json files. If no such documentation is
provided by the existing field OR if the field is a custom field, the
`FieldConfig.Documentation` configuration option is used for the field's
docstring in the Go type files.

Example usage for an existing nested field (from a hypothetical ec2
generator.yaml file). The
`LaunchTemplateData.HibernationOptions.Configured` field has a docstring
already that contains the following:

```
// If you set this parameter to true, the instance is enabled for hibernation.
//
// Default: false
```

Setting the `generator.yaml` file to the following:

```yaml
resources:
  LaunchTemplate:
    fields:
      LaunchTemplateData.HibernationOptions.Configured:
        documentation: XXX extended docs XXX
```

would cause the field's Documentation string to look like this:

```
// If you set this parameter to true, the instance is enabled for hibernation.
//
// Default: false
//
// XXX extended docs XXX",
```

Issue aws-controllers-k8s/community#1223

Signed-off-by: Jay Pipes <jaypipes@gmail.com>
  • Loading branch information
jaypipes authored Mar 10, 2023
1 parent 14dcc10 commit 338374e
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 6 deletions.
11 changes: 9 additions & 2 deletions pkg/config/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@

package config

import "strings"
import (
"strings"
)

// SourceFieldConfig instructs the code generator how to handle a field in the
// Resource's SpecFields/StatusFields collection that takes its value from an
Expand Down Expand Up @@ -390,10 +392,15 @@ type FieldConfig struct {
// TODO(jaypipes,crtbry): Figure out if we can roll the CustomShape stuff
// into this type override...
Type *string `json:"type,omitempty"`
// Documentation is a string that is added *in addition to* any existing
// field documentation derived from the field's doc-2.json contents. For
// custom fields, this allows you to add custom documentation for the
// field.
Documentation *string `json:"documentation,omitempty"`
}

// GetFieldConfigs returns all FieldConfigs for a given resource as a map.
// The map is keyed by the resource's field names after applying renames, if applicable.
// The map is keyed by the resource's field paths
func (c *Config) GetFieldConfigs(resourceName string) map[string]*FieldConfig {
if c == nil {
return map[string]*FieldConfig{}
Expand Down
59 changes: 59 additions & 0 deletions pkg/model/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,65 @@ type Field struct {
MemberFields map[string]*Field
}

// GetDocumentation returns a string containing the field's
// description/docstring. If the field has a ShapeRef that has non-empty
// Documentation AND the field has a Documentation configuration option, then
// the docstring contained in the Documentation configuration option will be
// appended to ShapeRef's docstring following 2 line breaks with Go comment
// line beginnings.
//
// In other words, if there is a field with a ShapeRef that has a Documentation string containing:
//
// "// This field contains the identifier for the cluster
//
// // running the cache services"
//
// and the field has a FieldConfig.Documentation string containing:
//
// "please note that this field is updated on the service
//
// side"
//
// then the string returned from this method will be:
//
// "// This field contains the identifier for the cluster
//
// // running the cache services
// //
// // please note that this field is updated on the service
// // side"
func (f *Field) GetDocumentation() string {
hasShapeDoc := false
var sb strings.Builder
if f.ShapeRef != nil {
if f.ShapeRef.Documentation != "" {
hasShapeDoc = true
sb.WriteString(f.ShapeRef.Documentation)
}
}
if f.FieldConfig != nil {
if f.FieldConfig.Documentation != nil {
if hasShapeDoc {
sb.WriteString("\n//\n")
}
// Strip any leading comment slashes from the config option
// docstring since we'll be automatically adding the Go comment
// slashes to the beginning of each new line
cfgDoc := *f.FieldConfig.Documentation
lines := strings.Split(cfgDoc, "\n")
numLines := len(lines)
for x, line := range lines {
sb.WriteString("// ")
sb.WriteString(strings.TrimLeft(line, "/ "))
if x < (numLines - 1) {
sb.WriteString("\n")
}
}
}
}
return sb.String()
}

// IsRequired checks the FieldConfig for Field and returns if the field is
// marked as required or not.A
//
Expand Down
45 changes: 45 additions & 0 deletions pkg/model/field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,51 @@ import (
"github.com/aws-controllers-k8s/code-generator/pkg/testutil"
)

func TestFieldDocumentation(t *testing.T) {
require := require.New(t)

g := testutil.NewModelForServiceWithOptions(t, "ec2",
&testutil.TestingModelOptions{
GeneratorConfigFile: "generator-with-doc-overrides.yaml",
},
)

crds, err := g.GetCRDs()
require.Nil(err)

crd := getCRDByName("LaunchTemplate", crds)
require.NotNil(crd)

specFields := crd.SpecFields

// We have not altered the docstring for LaunchTemplateData from the
// docstring that comes in the doc-2.json file...
ltdField := specFields["LaunchTemplateData"]
require.NotNil(ltdField)
require.NotNil(ltdField.ShapeRef)

require.Equal(
"// The information for the launch template.",
ltdField.GetDocumentation(),
)

// We have added an additional docstring for
// LaunchTemplateData.HibernationOptions.Configured to the docstring that
// comes in the doc-2.json file...
hoField := ltdField.MemberFields["HibernationOptions"]
require.NotNil(hoField)
require.NotNil(hoField.ShapeRef)
hocField := hoField.MemberFields["Configured"]
require.NotNil(hocField)
require.NotNil(hocField.ShapeRef)

require.Equal(
"// If you set this parameter to true, the instance is enabled for hibernation.\n// \n// Default: false\n//\n// XXX extended docs XXX",
hocField.GetDocumentation(),
)

}

func TestMemberFields(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
ignore:
resource_names:
- AccountAttribute
- CapacityReservation
- CarrierGateway
- ClientVpnEndpoint
- ClientVpnRoute
- CustomerGateway
- DefaultSubnet
- DefaultVpc
- DhcpOptions
- EgressOnlyInternetGateway
- Fleet
- FpgaImage
- Image
- Instance
- InstanceExportTask
- InternetGateway
- KeyPair
- LaunchTemplateVersion
#- LaunchTemplate
- LocalGatewayRouteTableVpcAssociation
- LocalGatewayRoute
- ManagedPrefixList
- NatGateway
- NetworkAclEntry
- NetworkAcl
- NetworkInsightsPath
- NetworkInterfacePermission
- NetworkInterface
- PlacementGroup
- ReservedInstancesListing
- RouteTable
- Route
- SecurityGroup
- Snapshot
- SpotDatafeedSubscription
- Subnet
- TrafficMirrorFilterRule
- TrafficMirrorFilter
- TrafficMirrorSession
- TrafficMirrorTarget
- TransitGatewayConnectPeer
- TransitGatewayConnect
- TransitGatewayMulticastDomain
- TransitGatewayPeeringAttachment
- TransitGatewayPrefixListReference
- TransitGatewayRouteTable
- TransitGatewayRoute
- TransitGatewayVpcAttachment
- TransitGateway
- Volume
- VpcEndpointConnectionNotification
- VpcEndpointServiceConfiguration
- VpcEndpoint
- Vpc
- VpcCidrBlock
- VpcPeeringConnection
- VpnConnectionRoute
- VpnConnection
- VpnGateway
resources:
LaunchTemplate:
fields:
LaunchTemplateData.HibernationOptions.Configured:
documentation: XXX extended docs XXX
8 changes: 4 additions & 4 deletions templates/apis/crd.go.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (
{{ .CRD.Documentation }}
type {{ .CRD.Kind }}Spec struct {
{{ range $fieldName, $field := .CRD.SpecFields }}
{{ if and ($field.ShapeRef) ($field.ShapeRef.Documentation) -}}
{{ $field.ShapeRef.Documentation }}
{{ if $field.GetDocumentation -}}
{{ $field.GetDocumentation }}
{{ end -}}
{{- if and ($field.IsRequired) (not $field.HasReference) -}}
// +kubebuilder:validation:Required
Expand All @@ -40,8 +40,8 @@ type {{ .CRD.Kind }}Status struct {
// +kubebuilder:validation:Optional
Conditions []*ackv1alpha1.Condition `json:"conditions"`
{{- range $fieldName, $field := .CRD.StatusFields }}
{{- if and ($field.ShapeRef) ($field.ShapeRef.Documentation) }}
{{ $field.ShapeRef.Documentation }}
{{- if $field.GetDocumentation }}
{{ $field.GetDocumentation }}
{{- end }}
// +kubebuilder:validation:Optional
{{ $field.Names.Camel }} {{ $field.GoType }} `json:"{{ $field.Names.CamelLower }},omitempty"`
Expand Down

0 comments on commit 338374e

Please sign in to comment.