Skip to content

Commit 6542e04

Browse files
Create separate documentation.yaml file (#447)
Closes aws-controllers-k8s/community#1223 Expands upon #394 Description of changes: This pull request moves the custom GoDoc overrides from inside the `generator.yaml` file to a new, separate `documentation.yaml` file. This `documentation.yaml` file currently supports modify field GoDocs (but could be extended to modify resource GoDocs as well) in the following ways: - Prepend: Add a comment before the existing shape ref GoDoc - Append: Add a comment after the existing shape ref GoDoc - Override: Completely replace the existing shape ref GoDoc The current RDS documentation modifications are now modeled in the `documentation.yaml` like so: ```yaml resources: DBClusterParameterGroup: fields: Parameters: override: | DEPRECATED - do not use. Prefer ParameterOverrides instead. ParameterOverrides: append: | These are ONLY user-defined parameter overrides for the DB cluster parameter group. This does not contain default or system parameters. DBParameterGroup: fields: ParameterOverrides: append: | These are ONLY user-defined parameter overrides for the DB parameter group. This does not contain default or system parameters. ``` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 9b75510 commit 6542e04

File tree

15 files changed

+265
-136
lines changed

15 files changed

+265
-136
lines changed

cmd/ack-generate/command/common.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,13 @@ func loadModel(svcAlias string, apiVersion string, apiGroup string, defaultCfg a
6868
sdkAPI.APIGroupSuffix = apiGroup
6969
}
7070

71+
docCfg, err := ackgenconfig.NewDocumentationConfig(optDocumentationConfigPath)
72+
if err != nil {
73+
return nil, err
74+
}
75+
7176
m, err := ackmodel.New(
72-
sdkAPI, svcAlias, apiVersion, cfg,
77+
sdkAPI, svcAlias, apiVersion, cfg, docCfg,
7378
)
7479
if err != nil {
7580
return nil, err

cmd/ack-generate/command/root.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,22 @@ A tool to generate AWS service controller code`
3030
)
3131

3232
var (
33-
defaultCacheDir string
34-
optCacheDir string
35-
optRefreshCache bool
36-
optAWSSDKGoVersion string
37-
defaultTemplateDirs []string
38-
optTemplateDirs []string
39-
defaultServicesDir string
40-
optServicesDir string
41-
optDryRun bool
42-
sdkDir string
43-
optGeneratorConfigPath string
44-
optMetadataConfigPath string
45-
optOutputPath string
46-
optServiceAccountName string
47-
optImageRepository string
33+
defaultCacheDir string
34+
optCacheDir string
35+
optRefreshCache bool
36+
optAWSSDKGoVersion string
37+
defaultTemplateDirs []string
38+
optTemplateDirs []string
39+
defaultServicesDir string
40+
optServicesDir string
41+
optDryRun bool
42+
sdkDir string
43+
optGeneratorConfigPath string
44+
optMetadataConfigPath string
45+
optDocumentationConfigPath string
46+
optOutputPath string
47+
optServiceAccountName string
48+
optImageRepository string
4849
)
4950

5051
var rootCmd = &cobra.Command{
@@ -117,6 +118,9 @@ func init() {
117118
rootCmd.PersistentFlags().StringVar(
118119
&optMetadataConfigPath, "metadata-config-path", "", "Path to file containing service metadata to use",
119120
)
121+
rootCmd.PersistentFlags().StringVar(
122+
&optDocumentationConfigPath, "documentation-config-path", "", "Path to file containing additions for the API documentation fields",
123+
)
120124
rootCmd.PersistentFlags().StringVarP(
121125
&optOutputPath, "output", "o", "", "Path to directory to output generated files (if generating crossplane providers, this should be the root of the aws-crossplane directory)",
122126
)

pkg/config/documentation.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package config
2+
3+
import (
4+
"io/ioutil"
5+
6+
"github.com/ghodss/yaml"
7+
)
8+
9+
// DocumentationConfig represents the configuration of the documentation file,
10+
// used to override or append documentation to any of the resource fields
11+
type DocumentationConfig struct {
12+
Resources map[string]*ResourceDocsConfig `json:"resources,omitempty"`
13+
}
14+
15+
// ResourceDocsConfig represents the configuration for the documentation
16+
// overrides of a single resource
17+
type ResourceDocsConfig struct {
18+
Fields map[string]*FieldDocsConfig `json:"fields,omitempty"`
19+
}
20+
21+
// FieldDocsConfig represents the configuration for the documentation overrides
22+
// of a single field
23+
type FieldDocsConfig struct {
24+
// Append specifies a string that will be added to the end of the existing
25+
// GoDoc comment for the field
26+
Append *string `json:"append,omitempty"`
27+
// Prepend specifies a string that will be added before the existing
28+
// GoDoc comment for the field
29+
Prepend *string `json:"prepend,omitempty"`
30+
// Override will entirely replace the GoDoc comment for the field
31+
Override *string `json:"override,omitempty"`
32+
}
33+
34+
// NewDocumentationConfig returns a new DocumentationConfig object given a
35+
// supplied path to a config file
36+
func NewDocumentationConfig(
37+
configPath string,
38+
) (DocumentationConfig, error) {
39+
if configPath == "" {
40+
return DocumentationConfig{}, nil
41+
}
42+
content, err := ioutil.ReadFile(configPath)
43+
if err != nil {
44+
return DocumentationConfig{}, err
45+
}
46+
gc := DocumentationConfig{}
47+
if err = yaml.Unmarshal(content, &gc); err != nil {
48+
return DocumentationConfig{}, err
49+
}
50+
return gc, nil
51+
}

pkg/config/field.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -405,11 +405,6 @@ type FieldConfig struct {
405405
// TODO(jaypipes,crtbry): Figure out if we can roll the CustomShape stuff
406406
// into this type override...
407407
Type *string `json:"type,omitempty"`
408-
// Documentation is a string that is added *in addition to* any existing
409-
// field documentation derived from the field's doc-2.json contents. For
410-
// custom fields, this allows you to add custom documentation for the
411-
// field.
412-
Documentation *string `json:"documentation,omitempty"`
413408
}
414409

415410
// GetFieldConfigs returns all FieldConfigs for a given resource as a map.

pkg/metadata/api_info.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ type APIInfo struct {
2929
AWSSDKVersion string
3030
// Full path of the generator config file.
3131
GeneratorConfigPath string
32+
// Full path of the documentation config file.
33+
DocumentationConfigPath string
3234
// The API version.
3335
APIVersion string
3436
}

pkg/model/crd.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ func (ops Ops) IterOps() []*awssdkmodel.Operation {
6464
type CRD struct {
6565
sdkAPI *SDKAPI
6666
cfg *ackgenconfig.Config
67+
docCfg *ackgenconfig.DocumentationConfig
6768
Names names.Names
6869
Kind string
6970
Plural string
@@ -785,6 +786,7 @@ func (r *CRD) SortedFieldNames() []string {
785786
func NewCRD(
786787
sdkAPI *SDKAPI,
787788
cfg *ackgenconfig.Config,
789+
docCfg *ackgenconfig.DocumentationConfig,
788790
crdNames names.Names,
789791
ops Ops,
790792
) *CRD {
@@ -794,6 +796,7 @@ func NewCRD(
794796
return &CRD{
795797
sdkAPI: sdkAPI,
796798
cfg: cfg,
799+
docCfg: docCfg,
797800
Names: crdNames,
798801
Kind: kind,
799802
Plural: plural,

pkg/model/field.go

Lines changed: 81 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,20 @@ type Field struct {
6565
}
6666

6767
// GetDocumentation returns a string containing the field's
68-
// description/docstring. If the field has a ShapeRef that has non-empty
69-
// Documentation AND the field has a Documentation configuration option, then
70-
// the docstring contained in the Documentation configuration option will be
71-
// appended to ShapeRef's docstring following 2 line breaks with Go comment
72-
// line beginnings.
68+
// description/docstring. The ShapeRef from the AWS SDK is used as the default
69+
// value for the documentation of the field. If a documentation override has
70+
// been provided (in the `documentation.yaml`) file, then it will either be
71+
// prependend or appended, or entirely overridden.
7372
//
74-
// In other words, if there is a field with a ShapeRef that has a Documentation string containing:
73+
// For example, if there is a field with a ShapeRef that has a Documentation
74+
// string containing:
7575
//
7676
// "// This field contains the identifier for the cluster
7777
//
78-
// // running the cache services"
78+
// running the cache services"
7979
//
80-
// and the field has a FieldConfig.Documentation string containing:
80+
// and the field has a documentation config specifies the following should be
81+
// appended:
8182
//
8283
// "please note that this field is updated on the service
8384
//
@@ -88,36 +89,76 @@ type Field struct {
8889
// "// This field contains the identifier for the cluster
8990
//
9091
// // running the cache services
91-
// //
9292
// // please note that this field is updated on the service
9393
// // side"
9494
func (f *Field) GetDocumentation() string {
95+
cfg := f.GetFieldDocsConfig()
96+
9597
hasShapeDoc := false
96-
var sb strings.Builder
98+
var prepend strings.Builder
99+
var out strings.Builder
100+
97101
if f.ShapeRef != nil {
98102
if f.ShapeRef.Documentation != "" {
99103
hasShapeDoc = true
100-
sb.WriteString(f.ShapeRef.Documentation)
104+
out.WriteString(f.ShapeRef.Documentation)
101105
}
102106
}
103-
if f.FieldConfig != nil {
104-
if f.FieldConfig.Documentation != nil {
105-
if hasShapeDoc {
106-
sb.WriteString("\n//\n")
107-
}
108-
// Strip any leading comment slashes from the config option
109-
// docstring since we'll be automatically adding the Go comment
110-
// slashes to the beginning of each new line
111-
cfgDoc := *f.FieldConfig.Documentation
112-
lines := strings.Split(cfgDoc, "\n")
113-
numLines := len(lines)
114-
for x, line := range lines {
115-
sb.WriteString("// ")
116-
sb.WriteString(strings.TrimLeft(line, "/ "))
117-
if x < (numLines - 1) {
118-
sb.WriteString("\n")
119-
}
120-
}
107+
if cfg == nil {
108+
return out.String()
109+
}
110+
111+
// Ensure configuration has exclusive options
112+
if cfg.Override != nil && (cfg.Append != nil || cfg.Prepend != nil) {
113+
panic("Documentation cannot contain override and prepend/append. Field: " + f.CRD.Kind)
114+
}
115+
116+
if cfg.Override != nil {
117+
return f.formatUserProvidedDocstring(*cfg.Override)
118+
}
119+
120+
if cfg.Append != nil {
121+
if hasShapeDoc {
122+
out.WriteString("\n//\n")
123+
}
124+
out.WriteString(f.formatUserProvidedDocstring(*cfg.Append))
125+
}
126+
127+
if cfg.Prepend != nil {
128+
prepend.WriteString(f.formatUserProvidedDocstring(*cfg.Prepend))
129+
if hasShapeDoc {
130+
prepend.WriteString("\n//\n")
131+
}
132+
}
133+
134+
return prepend.String() + out.String()
135+
}
136+
137+
// formatUserProvidedDocstring sanitises a doc string provided by the user so
138+
// that it fits the format of the existing AWS SDK GoDocs. This method will
139+
// split it by lines, strip it of leading whitespace and slashes and prepend
140+
// `//` to each line.
141+
func (f *Field) formatUserProvidedDocstring(in string) string {
142+
var sb strings.Builder
143+
// Strip any leading comment slashes from the config option
144+
// docstring since we'll be automatically adding the Go comment
145+
// slashes to the beginning of each new line
146+
lines := strings.Split(in, "\n")
147+
148+
// Traverse in reverse order until, deleting empty lines
149+
for i := len(lines) - 1; i >= 0; i-- {
150+
if strings.TrimSpace(lines[i]) != "" {
151+
break
152+
}
153+
lines = lines[:i]
154+
}
155+
156+
numLines := len(lines)
157+
for idx, line := range lines {
158+
sb.WriteString("// ")
159+
sb.WriteString(strings.TrimLeft(line, " \\\t/"))
160+
if idx < (numLines - 1) {
161+
sb.WriteString("\n")
121162
}
122163
}
123164
return sb.String()
@@ -164,6 +205,17 @@ func (f *Field) GetSetterConfig(opType OpType) *ackgenconfig.SetFieldConfig {
164205
return nil
165206
}
166207

208+
// GetFieldDocsConfig returns the field documentation configuration for the
209+
// current field if it exists, otherwise it returns nil.
210+
func (f *Field) GetFieldDocsConfig() *ackgenconfig.FieldDocsConfig {
211+
resourceConfig, exists := f.CRD.docCfg.Resources[f.CRD.Names.Camel]
212+
if !exists {
213+
return nil
214+
}
215+
216+
return resourceConfig.Fields[f.Path]
217+
}
218+
167219
// HasReference returns true if the supplied field *path* refers to a Field
168220
// that contains 'ReferencesConfig' i.e. has a corresponding reference field.
169221
// Ex:

pkg/model/field_test.go

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package model_test
22

33
import (
44
"fmt"
5+
"strings"
56
"testing"
67

78
"github.com/aws-controllers-k8s/pkg/names"
@@ -17,44 +18,57 @@ import (
1718
func TestFieldDocumentation(t *testing.T) {
1819
require := require.New(t)
1920

20-
g := testutil.NewModelForServiceWithOptions(t, "ec2",
21+
g := testutil.NewModelForServiceWithOptions(t, "eks",
2122
&testutil.TestingModelOptions{
22-
GeneratorConfigFile: "generator-with-doc-overrides.yaml",
23+
GeneratorConfigFile: "generator.yaml",
24+
DocumentationConfigFile: "documentation.yaml",
2325
},
2426
)
2527

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

29-
crd := getCRDByName("LaunchTemplate", crds)
31+
crd := getCRDByName("Cluster", crds)
3032
require.NotNil(crd)
3133

3234
specFields := crd.SpecFields
3335

34-
// We have not altered the docstring for LaunchTemplateData from the
36+
// We have not altered the docstring for Version from the
3537
// docstring that comes in the doc-2.json file...
36-
ltdField := specFields["LaunchTemplateData"]
38+
ltdField := specFields["Version"]
3739
require.NotNil(ltdField)
3840
require.NotNil(ltdField.ShapeRef)
3941

4042
require.Equal(
41-
"// The information for the launch template.",
43+
"// The desired Kubernetes version for your cluster. If you don't specify a value\n// here, the latest version available in Amazon EKS is used.",
4244
ltdField.GetDocumentation(),
4345
)
4446

45-
// We have added an additional docstring for
46-
// LaunchTemplateData.HibernationOptions.Configured to the docstring that
47-
// comes in the doc-2.json file...
48-
hoField := ltdField.MemberFields["HibernationOptions"]
49-
require.NotNil(hoField)
50-
require.NotNil(hoField.ShapeRef)
51-
hocField := hoField.MemberFields["Configured"]
52-
require.NotNil(hocField)
53-
require.NotNil(hocField.ShapeRef)
47+
prependField := crd.Fields["ResourcesVPCConfig.SecurityGroupIDs"]
48+
require.NotNil(prependField)
49+
require.NotNil(prependField.ShapeRef)
50+
51+
require.True(
52+
strings.HasPrefix(prependField.GetDocumentation(), "// !!! Let's take it from the top"),
53+
)
54+
55+
appendField := crd.Fields["RoleARN"]
56+
require.NotNil(appendField)
57+
require.NotNil(appendField.ShapeRef)
58+
59+
require.True(
60+
strings.HasSuffix(appendField.GetDocumentation(), "// !!! Hello earthlings! I have come to assume your permissions."),
61+
)
62+
63+
overrideField := crd.Fields["Identity.OIDC.Issuer"]
64+
require.NotNil(overrideField)
65+
require.NotNil(overrideField.ShapeRef)
5466

5567
require.Equal(
56-
"// If you set this parameter to true, the instance is enabled for hibernation.\n// \n// Default: false\n//\n// XXX extended docs XXX",
57-
hocField.GetDocumentation(),
68+
"// !!! All your docs has become mine\n"+
69+
"// \n"+
70+
"// That whitespace is entirely on purpose",
71+
overrideField.GetDocumentation(),
5872
)
5973

6074
}

0 commit comments

Comments
 (0)