Add stability level in the tags doc.

This commit is contained in:
Lalit Chauhan
2025-08-07 22:01:46 +00:00
parent 9630ab9581
commit d0f482129d
18 changed files with 108 additions and 59 deletions

View File

@@ -225,9 +225,10 @@ func (evtv eachValTagValidator) getMapValidations(t *types.Type, validations Val
func (evtv eachValTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: evtv.TagName(),
Scopes: evtv.ValidScopes().UnsortedList(),
Description: "Declares a validation for each value in a map or list.",
Tag: evtv.TagName(),
StabilityLevel: Alpha,
Scopes: evtv.ValidScopes().UnsortedList(),
Description: "Declares a validation for each value in a map or list.",
Payloads: []TagPayloadDoc{{
Description: "<validation-tag>",
Docs: "The tag to evaluate for each value.",
@@ -306,9 +307,10 @@ func ForEachKey(_ *field.Path, t *types.Type, fn FunctionGen) (Validations, erro
func (ektv eachKeyTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: ektv.TagName(),
Scopes: ektv.ValidScopes().UnsortedList(),
Description: "Declares a validation for each value in a map or list.",
Tag: ektv.TagName(),
Scopes: ektv.ValidScopes().UnsortedList(),
StabilityLevel: Alpha,
Description: "Declares a validation for each value in a map or list.",
Payloads: []TagPayloadDoc{{
Description: "<validation-tag>",
Docs: "The tag to evaluate for each key.",

View File

@@ -61,8 +61,9 @@ func (*enumExcludeTagValidator) GetValidations(_ Context, _ codetags.Tag) (Valid
func (eetv *enumExcludeTagValidator) Docs() TagDoc {
return TagDoc{
Tag: eetv.TagName(),
Scopes: eetv.ValidScopes().UnsortedList(),
Tag: eetv.TagName(),
StabilityLevel: Alpha,
Scopes: eetv.ValidScopes().UnsortedList(),
Description: `Indicates that an constant value is not part of an enum, even if the constant's type is tagged with k8s:enum.
May be conditionally excluded via +k8s:ifEnabled(Option)=+k8s:enumExclude or +k8s:ifDisabled(Option)=+k8s:enumExclude.
If multiple +k8s:ifEnabled/+k8s:ifDisabled tags are used, the value is excluded if any of the exclude conditions are met.`,
@@ -192,9 +193,10 @@ func (etv *enumTagValidator) GetValidations(context Context, _ codetags.Tag) (Va
func (etv *enumTagValidator) Docs() TagDoc {
return TagDoc{
Tag: etv.TagName(),
Scopes: etv.ValidScopes().UnsortedList(),
Description: "Indicates that a string type is an enum. All constant values of this type are considered values in the enum unless excluded using +k8s:enumExclude.",
Tag: etv.TagName(),
StabilityLevel: Beta,
Scopes: etv.ValidScopes().UnsortedList(),
Description: "Indicates that a string type is an enum. All constant values of this type are considered values in the enum unless excluded using +k8s:enumExclude.",
}
}

View File

@@ -98,6 +98,7 @@ func (v neqTagValidator) GetValidations(context Context, tag codetags.Tag) (Vali
func (v neqTagValidator) Docs() TagDoc {
return TagDoc{
Tag: v.TagName(),
StabilityLevel: Alpha,
Scopes: v.ValidScopes().UnsortedList(),
Description: "Verifies the field's value is not equal to a specific disallowed value. Supports string, integer, and boolean types.",
PayloadsRequired: true,

View File

@@ -113,9 +113,10 @@ func getFormatValidationFunction(format string) (FunctionGen, error) {
func (ftv formatTagValidator) Docs() TagDoc {
return TagDoc{
Tag: ftv.TagName(),
Scopes: ftv.ValidScopes().UnsortedList(),
Description: "Indicates that a string field has a particular format.",
Tag: ftv.TagName(),
StabilityLevel: Beta,
Scopes: ftv.ValidScopes().UnsortedList(),
Description: "Indicates that a string field has a particular format.",
Payloads: []TagPayloadDoc{{ // Keep this list alphabetized.
Description: "k8s-ip",
Docs: "This field holds an IPv4 or IPv6 address value. IPv4 octets may have leading zeros.",

View File

@@ -58,8 +58,9 @@ func (immutableTagValidator) GetValidations(context Context, _ codetags.Tag) (Va
func (itv immutableTagValidator) Docs() TagDoc {
return TagDoc{
Tag: itv.TagName(),
Scopes: itv.ValidScopes().UnsortedList(),
Description: "Indicates that a field may not be updated.",
Tag: itv.TagName(),
StabilityLevel: Alpha,
Scopes: itv.ValidScopes().UnsortedList(),
Description: "Indicates that a field may not be updated.",
}
}

View File

@@ -248,8 +248,9 @@ func parseTypedValue(value string, argType codetags.ArgType) (any, codetags.Valu
func (itv itemTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: itv.TagName(),
Scopes: itv.ValidScopes().UnsortedList(),
Tag: itv.TagName(),
StabilityLevel: Alpha,
Scopes: itv.ValidScopes().UnsortedList(),
Description: "Declares a validation for an item of a slice declared as a +k8s:listType=map. " +
"The item to match is declared by providing field-value pair arguments. All key fields must be specified.",
Usage: "+k8s:item(stringKey: \"value\", intKey: 42, boolKey: true)=<validation-tag>",

View File

@@ -81,9 +81,10 @@ func (maxItemsTagValidator) GetValidations(context Context, tag codetags.Tag) (V
func (mitv maxItemsTagValidator) Docs() TagDoc {
return TagDoc{
Tag: mitv.TagName(),
Scopes: mitv.ValidScopes().UnsortedList(),
Description: "Indicates that a list has a limit on its size.",
Tag: mitv.TagName(),
StabilityLevel: Beta,
Scopes: mitv.ValidScopes().UnsortedList(),
Description: "Indicates that a list has a limit on its size.",
Payloads: []TagPayloadDoc{{
Description: "<non-negative integer>",
Docs: "This list must be no more than X items long.",
@@ -130,9 +131,10 @@ func (minimumTagValidator) GetValidations(context Context, tag codetags.Tag) (Va
func (mtv minimumTagValidator) Docs() TagDoc {
return TagDoc{
Tag: mtv.TagName(),
Scopes: mtv.ValidScopes().UnsortedList(),
Description: "Indicates that a numeric field has a minimum value.",
Tag: mtv.TagName(),
StabilityLevel: Beta,
Scopes: mtv.ValidScopes().UnsortedList(),
Description: "Indicates that a numeric field has a minimum value.",
Payloads: []TagPayloadDoc{{
Description: "<integer>",
Docs: "This field must be greater than or equal to x.",

View File

@@ -171,9 +171,10 @@ func (lttv listTypeTagValidator) GetValidations(context Context, tag codetags.Ta
func (lttv listTypeTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: lttv.TagName(),
Scopes: lttv.ValidScopes().UnsortedList(),
Description: "Declares a list field's semantic type and ownership behavior. atomic: single ownership, set: shared ownership with uniqueness, map: shared ownership with key-based uniqueness.",
Tag: lttv.TagName(),
StabilityLevel: Beta,
Scopes: lttv.ValidScopes().UnsortedList(),
Description: "Declares a list field's semantic type and ownership behavior. atomic: single ownership, set: shared ownership with uniqueness, map: shared ownership with key-based uniqueness.",
Payloads: []TagPayloadDoc{{
Description: "<type>",
Docs: "atomic | map | set",
@@ -233,9 +234,10 @@ func (lmktv listMapKeyTagValidator) GetValidations(context Context, tag codetags
func (lmktv listMapKeyTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: lmktv.TagName(),
Scopes: lmktv.ValidScopes().UnsortedList(),
Description: "Declares a named sub-field of a list's value-type to be part of the list-map key.",
Tag: lmktv.TagName(),
StabilityLevel: Beta,
Scopes: lmktv.ValidScopes().UnsortedList(),
Description: "Declares a named sub-field of a list's value-type to be part of the list-map key.",
Payloads: []TagPayloadDoc{{
Description: "<field-json-name>",
Docs: "The name of the field.",
@@ -301,9 +303,10 @@ func (utv uniqueTagValidator) GetValidations(context Context, tag codetags.Tag)
func (utv uniqueTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: utv.TagName(),
Scopes: utv.ValidScopes().UnsortedList(),
Description: "Declares that a list field's elements are unique. This tag can be used with listType=atomic to add uniqueness constraints, or independently to specify uniqueness semantics.",
Tag: utv.TagName(),
StabilityLevel: Alpha,
Scopes: utv.ValidScopes().UnsortedList(),
Description: "Declares that a list field's elements are unique. This tag can be used with listType=atomic to add uniqueness constraints, or independently to specify uniqueness semantics.",
Payloads: []TagPayloadDoc{{
Description: "<type>",
Docs: "map | set",
@@ -350,10 +353,11 @@ func (cutv customUniqueTagValidator) GetValidations(context Context, tag codetag
func (cutv customUniqueTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: cutv.TagName(),
Scopes: cutv.ValidScopes().UnsortedList(),
Description: "Indicates that uniqueness validation for this list is implemented via custom, handwritten validation. This disables generation of uniqueness validation for this list.",
Payloads: nil,
Tag: cutv.TagName(),
StabilityLevel: Alpha,
Scopes: cutv.ValidScopes().UnsortedList(),
Description: "Indicates that uniqueness validation for this list is implemented via custom, handwritten validation. This disables generation of uniqueness validation for this list.",
Payloads: nil,
}
return doc
}

View File

@@ -47,8 +47,9 @@ func (opaqueTypeTagValidator) GetValidations(_ Context, _ codetags.Tag) (Validat
func (opaqueTypeTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: opaqueTypeTagName,
Scopes: []Scope{ScopeField},
Tag: opaqueTypeTagName,
StabilityLevel: Alpha,
Scopes: []Scope{ScopeField},
Description: "Indicates that any validations declared on the referenced type will be ignored. " +
"If a referenced type's package is not included in the generator's current " +
"flags, this tag must be set, or code generation will fail (preventing silent " +

View File

@@ -80,7 +80,8 @@ func (itv ifTagValidator) GetValidations(context Context, tag codetags.Tag) (Val
func (itv ifTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: itv.TagName(),
Tag: itv.TagName(),
StabilityLevel: Alpha,
Args: []TagArgDoc{{
Description: "<option>",
Type: codetags.ArgTypeString,

View File

@@ -58,6 +58,14 @@ func (reg *registry) addTagValidator(tv TagValidator) {
if _, exists := globalRegistry.tagValidators[name]; exists {
panic(fmt.Sprintf("tag %q was registered twice", name))
}
switch level := tv.Docs().StabilityLevel; level {
case Alpha, Beta, Stable:
// valid
case "":
panic(fmt.Sprintf("tag %q is missing stability level", name))
default:
panic(fmt.Sprintf("tag %q has invalid stability level %q", name, level))
}
globalRegistry.tagValidators[name] = tv
}

View File

@@ -309,10 +309,13 @@ func (rtv requirednessTagValidator) Docs() TagDoc {
switch rtv.mode {
case requirednessRequired:
doc.StabilityLevel = Beta
doc.Description = "Indicates that a field must be specified by clients."
case requirednessOptional:
doc.StabilityLevel = Beta
doc.Description = "Indicates that a field is optional to clients."
case requirednessForbidden:
doc.StabilityLevel = Alpha
doc.Description = "Indicates that a field may not be specified."
default:
panic(fmt.Sprintf("unknown requiredness mode: %q", rtv.mode))

View File

@@ -133,9 +133,10 @@ func (stv subfieldTagValidator) GetValidations(context Context, tag codetags.Tag
func (stv subfieldTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: stv.TagName(),
Scopes: stv.ValidScopes().UnsortedList(),
Description: "Declares a validation for a subfield of a struct.",
Tag: stv.TagName(),
StabilityLevel: Alpha,
Scopes: stv.ValidScopes().UnsortedList(),
Description: "Declares a validation for a subfield of a struct.",
Args: []TagArgDoc{{
Description: "<field-json-name>",
Type: codetags.ArgTypeString,

View File

@@ -126,8 +126,9 @@ func (fixedResultTagValidator) toFixedResultArgs(in codetags.Tag) (fixedResultAr
func (frtv fixedResultTagValidator) Docs() TagDoc {
doc := TagDoc{
Tag: frtv.TagName(),
Scopes: frtv.ValidScopes().UnsortedList(),
Tag: frtv.TagName(),
StabilityLevel: Alpha,
Scopes: frtv.ValidScopes().UnsortedList(),
}
doc.PayloadsType = codetags.ValueTypeString
if frtv.error {

View File

@@ -116,9 +116,10 @@ func (udtv unionDiscriminatorTagValidator) GetValidations(context Context, tag c
func (udtv unionDiscriminatorTagValidator) Docs() TagDoc {
return TagDoc{
Tag: udtv.TagName(),
Scopes: udtv.ValidScopes().UnsortedList(),
Description: "Indicates that this field is the discriminator for a union.",
Tag: udtv.TagName(),
StabilityLevel: Alpha,
Scopes: udtv.ValidScopes().UnsortedList(),
Description: "Indicates that this field is the discriminator for a union.",
Args: []TagArgDoc{{
Name: "union",
Description: "<string>",
@@ -154,9 +155,10 @@ func (umtv unionMemberTagValidator) GetValidations(context Context, tag codetags
func (umtv unionMemberTagValidator) Docs() TagDoc {
return TagDoc{
Tag: umtv.TagName(),
Scopes: umtv.ValidScopes().UnsortedList(),
Description: "Indicates that this field is a member of a union.",
Tag: umtv.TagName(),
StabilityLevel: Alpha,
Scopes: umtv.ValidScopes().UnsortedList(),
Description: "Indicates that this field is a member of a union.",
Args: []TagArgDoc{{
Name: "union",
Description: "<string>",

View File

@@ -124,9 +124,10 @@ func constraintName(c validate.UpdateConstraint) string {
func (utc updateTagCollector) Docs() TagDoc {
return TagDoc{
Tag: utc.TagName(),
Scopes: utc.ValidScopes().UnsortedList(),
PayloadsType: codetags.ValueTypeString,
Tag: utc.TagName(),
StabilityLevel: Alpha,
Scopes: utc.ValidScopes().UnsortedList(),
PayloadsType: codetags.ValueTypeString,
Description: "Provides constraints on the allowed update operations of a field. " +
"Currently supports non-list and non-map fields only. " +
"Constraints: NoSet (prevents unset->set transitions), NoUnset (prevents set->unset transitions), " +

View File

@@ -247,10 +247,26 @@ type ListSelectorTerm struct {
Value any
}
// StabilityLevel indicates the stability of a validation tag.
type StabilityLevel string
const (
// Alpha indicates that a tag's semantics may change in the future.
Alpha StabilityLevel = "Alpha"
// Beta indicates that a tag's semantics will remain unchanged for the
// foreseeable future. This is used for soaking tags before qualifying to stable.
Beta StabilityLevel = "Beta"
// Stable indicates that a tag's semantics will remain unchanged for the
// foreseeable future.
Stable StabilityLevel = "Stable"
)
// TagDoc describes a comment-tag and its usage.
type TagDoc struct {
// Tag is the tag name, without the leading '+'.
Tag string
// StabilityLevel is the stability level of the tag.
StabilityLevel StabilityLevel
// Args lists any arguments this tag might take.
Args []TagArgDoc
// Usage is how the tag is used, including arguments.

View File

@@ -94,10 +94,11 @@ func (zmtv zeroOrOneOfMemberTagValidator) GetValidations(context Context, tag co
func (zmtv zeroOrOneOfMemberTagValidator) Docs() TagDoc {
return TagDoc{
Tag: zmtv.TagName(),
Scopes: zmtv.ValidScopes().UnsortedList(),
Description: "Indicates that this field is a member of a zero-or-one-of union.",
Docs: "A zero-or-one-of union allows at most one member to be set. Unlike regular unions, having no members set is valid.",
Tag: zmtv.TagName(),
Scopes: zmtv.ValidScopes().UnsortedList(),
StabilityLevel: Alpha,
Description: "Indicates that this field is a member of a zero-or-one-of union.",
Docs: "A zero-or-one-of union allows at most one member to be set. Unlike regular unions, having no members set is valid.",
Args: []TagArgDoc{{
Name: "union",
Description: "<string>",