-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Generate Docs fo Dynamic Configs #8861
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ type ( | |
| settingType struct { | ||
| Name string | ||
| GoType string | ||
| TypeName string // lowercase type name for documentation | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the value in having an extra value here over just using the Go type via reflection?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. forgot why I added it, I'll see if i can remove it |
||
| IsGeneric bool | ||
| } | ||
| settingPrecedence struct { | ||
|
|
@@ -31,32 +32,39 @@ var ( | |
| data = dynamicConfigData{ | ||
| Types: []settingType{ | ||
| { | ||
| Name: "Bool", | ||
| GoType: "bool", | ||
| Name: "Bool", | ||
| GoType: "bool", | ||
| TypeName: "bool", | ||
| }, | ||
| { | ||
| Name: "Int", | ||
| GoType: "int", | ||
| Name: "Int", | ||
| GoType: "int", | ||
| TypeName: "int", | ||
| }, | ||
| { | ||
| Name: "Float", | ||
| GoType: "float64", | ||
| Name: "Float", | ||
| GoType: "float64", | ||
| TypeName: "float", | ||
| }, | ||
| { | ||
| Name: "String", | ||
| GoType: "string", | ||
| Name: "String", | ||
| GoType: "string", | ||
| TypeName: "string", | ||
| }, | ||
| { | ||
| Name: "Duration", | ||
| GoType: "time.Duration", | ||
| Name: "Duration", | ||
| GoType: "time.Duration", | ||
| TypeName: "duration", | ||
| }, | ||
| { | ||
| Name: "Map", | ||
| GoType: "map[string]any", | ||
| Name: "Map", | ||
| GoType: "map[string]any", | ||
| TypeName: "map", | ||
| }, | ||
| { | ||
| Name: "Typed", | ||
| GoType: "<generic>", | ||
| TypeName: "typed", | ||
| IsGeneric: true, // this one is treated differently | ||
| }, | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,12 @@ | |
|
|
||
| package dynamicconfig | ||
|
|
||
| import ( | ||
| "reflect" | ||
| "strings" | ||
| "time" | ||
| ) | ||
|
|
||
| type ( | ||
| // Precedence is an enum for the search order precedence of a dynamic config setting. | ||
| // E.g., use the global value, check namespace then global, check task queue then | ||
|
|
@@ -27,13 +33,23 @@ type ( | |
| description string // documentation | ||
| } | ||
|
|
||
| // SettingDoc contains documentation metadata for a dynamic config setting. | ||
| SettingDoc struct { | ||
| Key string // setting key name | ||
| Type string // setting value type (e.g., "bool", "int", "duration", "string", "float", "map", "typed") | ||
| Precedence string // setting precedence (e.g., "Global", "Namespace", "TaskQueue") | ||
| Description string // human-readable description | ||
| DefaultValue any // default value (simple value or []TypedConstrainedValue for constrained defaults) | ||
| } | ||
|
|
||
| // GenericSetting is an interface that all instances of Setting implement (by generated | ||
| // code in setting_gen.go). It can be used to refer to settings of any type and deal with | ||
| // them generically.. | ||
| GenericSetting interface { | ||
| Key() Key | ||
| Precedence() Precedence | ||
| Validate(v any) error | ||
| Documentation() SettingDoc | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are already getters for Key and Precedence, let's just add new individual getters for description and default value instead of a new struct |
||
|
|
||
| // for internal use: | ||
| dispatchUpdate(*Collection, any, []ConstrainedValue) | ||
|
|
@@ -48,3 +64,90 @@ type ( | |
| DynamicConfigParseHook(S) (T, error) | ||
| } | ||
| ) | ||
|
|
||
| // formatDefaultValue formats a default value for display, converting durations to strings | ||
| func formatDefaultValue(v any) any { | ||
| if d, ok := v.(time.Duration); ok { | ||
| return d.String() | ||
| } | ||
| return v | ||
| } | ||
|
|
||
| // formatConstrainedDefaults formats constrained default values, converting durations to strings | ||
| func formatConstrainedDefaults[T any](cdef []TypedConstrainedValue[T]) any { | ||
| // Create a copy with formatted values | ||
| result := make([]TypedConstrainedValue[any], len(cdef)) | ||
| for i, cv := range cdef { | ||
| result[i] = TypedConstrainedValue[any]{ | ||
| Constraints: cv.Constraints, | ||
| Value: formatDefaultValue(cv.Value), | ||
| } | ||
| } | ||
| return result | ||
| } | ||
|
|
||
| // getTypeName returns a human-readable type name for documentation. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is all this complexity worth it instead of just fmt.Sprintf("%T", v)?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll see if I can remove it. |
||
| func getTypeName(v any) string { | ||
| t := reflect.TypeOf(v) | ||
| if t == nil { | ||
| return "any" | ||
| } | ||
|
|
||
| // Handle common types | ||
| switch t.Kind() { | ||
| case reflect.Bool: | ||
| return "bool" | ||
| case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||
| // Special case for time.Duration | ||
| if t.String() == "time.Duration" { | ||
| return "duration" | ||
| } | ||
| return "int" | ||
| case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||
| return "int" | ||
| case reflect.Float32, reflect.Float64: | ||
| return "float" | ||
| case reflect.String: | ||
| return "string" | ||
| case reflect.Map: | ||
| keyType := getTypeNameFromType(t.Key()) | ||
| valueType := getTypeNameFromType(t.Elem()) | ||
| return "map[" + keyType + "]" + valueType | ||
| case reflect.Slice: | ||
| elemType := getTypeNameFromType(t.Elem()) | ||
| return "[]" + elemType | ||
| case reflect.Struct: | ||
| // Check for time.Duration and other known structs | ||
| typeName := t.String() | ||
| if strings.Contains(typeName, ".") { | ||
| // Remove package prefix for cleaner names | ||
| parts := strings.Split(typeName, ".") | ||
| return strings.ToLower(parts[len(parts)-1]) | ||
| } | ||
| return "struct" | ||
| case reflect.Ptr: | ||
| // For pointer types, get the type of what it points to | ||
| return getTypeNameFromType(t.Elem()) | ||
| default: | ||
| return "typed" | ||
| } | ||
| } | ||
|
|
||
| // getTypeNameFromType returns a type name from a reflect.Type | ||
| func getTypeNameFromType(t reflect.Type) string { | ||
| // Handle interface types (like any/interface{}) | ||
| if t.Kind() == reflect.Interface { | ||
| if t.String() == "interface {}" { | ||
| return "any" | ||
| } | ||
| return t.String() | ||
| } | ||
|
|
||
| // Create a zero value and get its type name | ||
| if t.Kind() == reflect.Ptr { | ||
| // For pointer types, dereference | ||
| return getTypeNameFromType(t.Elem()) | ||
| } | ||
|
|
||
| return getTypeName(reflect.Zero(t).Interface()) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Integrate this with the validate-dynamic-config command above (probably move that one into here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll pull in render-config as well