Skip to content

Commit d0babe2

Browse files
committed
Prerelease lifecycle generator updates
Logs at lower verbosity to match other generators Switches major/minor return types to int Prefixes generated method names with APILifecycle to avoid collisions Adds a k8s:prerelease-lifecycle-gen:replacement=group,version,kind tag for indicating a replacement API
1 parent 875d3b5 commit d0babe2

File tree

1 file changed

+81
-20
lines changed
  • staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators

1 file changed

+81
-20
lines changed

staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status.go

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const (
4343
introducedTagName = tagEnabledName + ":introduced"
4444
deprecatedTagName = tagEnabledName + ":deprecated"
4545
removedTagName = tagEnabledName + ":removed"
46+
47+
replacementTagName = tagEnabledName + ":replacement"
4648
)
4749

4850
// enabledTagValue holds parameters from a tagName tag.
@@ -61,7 +63,7 @@ func tagExists(tagName string, t *types.Type) bool {
6163
return rawTag != nil
6264
}
6365

64-
func extractKubeVersionTag(tagName string, t *types.Type) (*tagValue, int64, int64, error) {
66+
func extractKubeVersionTag(tagName string, t *types.Type) (*tagValue, int, int, error) {
6567
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
6668
rawTag := extractTag(tagName, comments)
6769
if rawTag == nil || len(rawTag.value) == 0 {
@@ -72,30 +74,66 @@ func extractKubeVersionTag(tagName string, t *types.Type) (*tagValue, int64, int
7274
if len(splitValue) != 2 || len(splitValue[0]) == 0 || len(splitValue[0]) == 0 {
7375
return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy tag", t, tagName)
7476
}
75-
major, err := strconv.ParseInt(splitValue[0], 10, 64)
77+
major, err := strconv.ParseInt(splitValue[0], 10, 32)
7678
if err != nil {
7779
return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy : %w", t, tagName, err)
7880
}
79-
minor, err := strconv.ParseInt(splitValue[1], 10, 64)
81+
minor, err := strconv.ParseInt(splitValue[1], 10, 32)
8082
if err != nil {
8183
return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy : %w", t, tagName, err)
8284
}
8385

84-
return rawTag, major, minor, nil
86+
return rawTag, int(major), int(minor), nil
8587
}
8688

87-
func extractIntroducedTag(t *types.Type) (*tagValue, int64, int64, error) {
89+
func extractIntroducedTag(t *types.Type) (*tagValue, int, int, error) {
8890
return extractKubeVersionTag(introducedTagName, t)
8991
}
9092

91-
func extractDeprecatedTag(t *types.Type) (*tagValue, int64, int64, error) {
93+
func extractDeprecatedTag(t *types.Type) (*tagValue, int, int, error) {
9294
return extractKubeVersionTag(deprecatedTagName, t)
9395
}
9496

95-
func extractRemovedTag(t *types.Type) (*tagValue, int64, int64, error) {
97+
func extractRemovedTag(t *types.Type) (*tagValue, int, int, error) {
9698
return extractKubeVersionTag(removedTagName, t)
9799
}
98100

101+
func extractReplacementTag(t *types.Type) (group, version, kind string, hasReplacement bool, err error) {
102+
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
103+
104+
tagVals := types.ExtractCommentTags("+", comments)[replacementTagName]
105+
if len(tagVals) == 0 {
106+
// No match for the tag.
107+
return "", "", "", false, nil
108+
}
109+
// If there are multiple values, abort.
110+
if len(tagVals) > 1 {
111+
return "", "", "", false, fmt.Errorf("Found %d %s tags: %q", len(tagVals), replacementTagName, tagVals)
112+
}
113+
tagValue := tagVals[0]
114+
parts := strings.Split(tagValue, ",")
115+
if len(parts) != 3 {
116+
return "", "", "", false, fmt.Errorf(`%s value must be "<group>,<version>,<kind>", got %q`, replacementTagName, tagValue)
117+
}
118+
group, version, kind = parts[0], parts[1], parts[2]
119+
if len(version) == 0 || len(kind) == 0 {
120+
return "", "", "", false, fmt.Errorf(`%s value must be "<group>,<version>,<kind>", got %q`, replacementTagName, tagValue)
121+
}
122+
// sanity check the group
123+
if strings.ToLower(group) != group {
124+
return "", "", "", false, fmt.Errorf(`replacement group must be all lower-case, got %q`, group)
125+
}
126+
// sanity check the version
127+
if !strings.HasPrefix(version, "v") || strings.ToLower(version) != version {
128+
return "", "", "", false, fmt.Errorf(`replacement version must start with "v" and be all lower-case, got %q`, version)
129+
}
130+
// sanity check the kind
131+
if strings.ToUpper(kind[:1]) != kind[:1] {
132+
return "", "", "", false, fmt.Errorf(`replacement kind must start with uppercase-letter, got %q`, kind)
133+
}
134+
return group, version, kind, true, nil
135+
}
136+
99137
func extractTag(tagName string, comments []string) *tagValue {
100138
tagVals := types.ExtractCommentTags("+", comments)[tagName]
101139
if tagVals == nil {
@@ -182,7 +220,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
182220
klog.V(5).Infof(" skipping package")
183221
continue
184222
}
185-
klog.Infof("Generating package %q", pkg.Path)
223+
klog.V(3).Infof("Generating package %q", pkg.Path)
186224

187225
// If the pkg-scoped tag says to generate, we can skip scanning types.
188226
if !pkgNeedsGeneration {
@@ -356,7 +394,7 @@ func (g *genPreleaseLifecycle) Imports(c *generator.Context) (imports []string)
356394
return importLines
357395
}
358396

359-
func argsFromType(t *types.Type) (generator.Args, error) {
397+
func (g *genPreleaseLifecycle) argsFromType(c *generator.Context, t *types.Type) (generator.Args, error) {
360398
a := generator.Args{
361399
"type": t,
362400
}
@@ -396,6 +434,20 @@ func argsFromType(t *types.Type) (generator.Args, error) {
396434
With("removedMajor", removedMajor).
397435
With("removedMinor", removedMinor)
398436

437+
replacementGroup, replacementVersion, replacementKind, hasReplacement, err := extractReplacementTag(t)
438+
if err != nil {
439+
return nil, err
440+
}
441+
if hasReplacement {
442+
gvkType := c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionKind"})
443+
g.imports.AddType(gvkType)
444+
a = a.
445+
With("replacementGroup", replacementGroup).
446+
With("replacementVersion", replacementVersion).
447+
With("replacementKind", replacementKind).
448+
With("GroupVersionKind", gvkType)
449+
}
450+
399451
return a, nil
400452
}
401453

@@ -404,32 +456,41 @@ func (g *genPreleaseLifecycle) Init(c *generator.Context, w io.Writer) error {
404456
}
405457

406458
func (g *genPreleaseLifecycle) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
407-
klog.Infof("Generating prerelease-lifecycle for type %v", t)
459+
klog.V(3).Infof("Generating prerelease-lifecycle for type %v", t)
408460

409461
sw := generator.NewSnippetWriter(w, c, "$", "$")
410-
args, err := argsFromType(t)
462+
args, err := g.argsFromType(c, t)
411463
if err != nil {
412464
return err
413465
}
414466

415-
if versionedMethodOrDie("Introduced", t) == nil {
416-
sw.Do("// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison.\n", args)
467+
if versionedMethodOrDie("APILifecycleIntroduced", t) == nil {
468+
sw.Do("// APILifecycleIntroduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison.\n", args)
417469
sw.Do("// It is controlled by \""+introducedTagName+"\" tags in types.go.\n", args)
418-
sw.Do("func (in *$.type|intrapackage$) Introduced() (int64, int64) {\n", args)
470+
sw.Do("func (in *$.type|intrapackage$) APILifecycleIntroduced() (major, minor int) {\n", args)
419471
sw.Do(" return $.introducedMajor$, $.introducedMinor$\n", args)
420472
sw.Do("}\n\n", nil)
421473
}
422-
if versionedMethodOrDie("Deprecated", t) == nil {
423-
sw.Do("// Deprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.\n", args)
474+
if versionedMethodOrDie("APILifecycleDeprecated", t) == nil {
475+
sw.Do("// APILifecycleDeprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.\n", args)
424476
sw.Do("// It is controlled by \""+deprecatedTagName+"\" tags in types.go or \""+introducedTagName+"\" plus three minor.\n", args)
425-
sw.Do("func (in *$.type|intrapackage$) Deprecated() (int64, int64) {\n", args)
477+
sw.Do("func (in *$.type|intrapackage$) APILifecycleDeprecated() (major, minor int) {\n", args)
426478
sw.Do(" return $.deprecatedMajor$, $.deprecatedMinor$\n", args)
427479
sw.Do("}\n\n", nil)
428480
}
429-
if versionedMethodOrDie("Removed", t) == nil {
430-
sw.Do("// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.\n", args)
481+
if _, hasReplacement := args["replacementKind"]; hasReplacement {
482+
if versionedMethodOrDie("APILifecycleReplacement", t) == nil {
483+
sw.Do("// APILifecycleReplacement is an autogenerated function, returning the group, version, and kind that should be used instead of this deprecated type.\n", args)
484+
sw.Do("// It is controlled by \""+replacementTagName+"=<group>,<version>,<kind>\" tags in types.go.\n", args)
485+
sw.Do("func (in *$.type|intrapackage$) APILifecycleReplacement() ($.GroupVersionKind|raw$) {\n", args)
486+
sw.Do(" return $.GroupVersionKind|raw${Group:\"$.replacementGroup$\", Version:\"$.replacementVersion$\", Kind:\"$.replacementKind$\"}\n", args)
487+
sw.Do("}\n\n", nil)
488+
}
489+
}
490+
if versionedMethodOrDie("APILifecycleRemoved", t) == nil {
491+
sw.Do("// APILifecycleRemoved is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.\n", args)
431492
sw.Do("// It is controlled by \""+removedTagName+"\" tags in types.go or \""+deprecatedTagName+"\" plus three minor.\n", args)
432-
sw.Do("func (in *$.type|intrapackage$) Removed() (int64, int64) {\n", args)
493+
sw.Do("func (in *$.type|intrapackage$) APILifecycleRemoved() (major, minor int) {\n", args)
433494
sw.Do(" return $.removedMajor$, $.removedMinor$\n", args)
434495
sw.Do("}\n\n", nil)
435496
}

0 commit comments

Comments
 (0)