-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
[cmd/mdatagen]: Add feature gates support to metadata-schema.yaml #11466
base: main
Are you sure you want to change the base?
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 |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
"fmt" | ||
"os/exec" | ||
"path/filepath" | ||
"regexp" | ||
"strings" | ||
|
||
"go.opentelemetry.io/collector/component" | ||
|
@@ -20,6 +21,20 @@ | |
"go.opentelemetry.io/collector/pdata/pcommon" | ||
) | ||
|
||
var ( | ||
// idRegexp is used to validate the ID of a Gate. | ||
// IDs' characters must be alphanumeric or dots. | ||
idRegexp = regexp.MustCompile(`^[0-9a-zA-Z\.]*$`) | ||
versionRegexp = regexp.MustCompile(`^v(\d+)\.(\d+)\.(\d+)$`) | ||
referenceURLRegexp = regexp.MustCompile(`^(https?:\/\/)?([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+)(\/[^\s]*)?$`) | ||
validStages = map[string]bool{ | ||
"Alpha": true, | ||
"Beta": true, | ||
"Stable": true, | ||
"Deprecated": true, | ||
} | ||
) | ||
|
||
type MetricName string | ||
|
||
func (mn MetricName) Render() (string, error) { | ||
|
@@ -40,6 +55,16 @@ | |
return FormatIdentifier(string(mn), false) | ||
} | ||
|
||
type featureGateName string | ||
|
||
func (mn featureGateName) Render() (string, error) { | ||
return FormatIdentifier(string(mn), true) | ||
} | ||
|
||
func (mn featureGateName) RenderUnexported() (string, error) { | ||
return FormatIdentifier(string(mn), false) | ||
} | ||
|
||
// ValueType defines an attribute value type. | ||
type ValueType struct { | ||
// ValueType is type of the attribute value. | ||
|
@@ -159,6 +184,7 @@ | |
} | ||
return parser.Unmarshal(m) | ||
} | ||
|
||
func (m Metric) Data() MetricData { | ||
if m.Sum != nil { | ||
return m.Sum | ||
|
@@ -296,6 +322,8 @@ | |
ShortFolderName string `mapstructure:"-"` | ||
// Tests is the set of tests generated with the component | ||
Tests tests `mapstructure:"tests"` | ||
// FeatureGates that can be used for the component. | ||
FeatureGates map[featureGateName]featureGate `mapstructure:"feature_gates"` | ||
} | ||
|
||
func setAttributesFullName(attrs map[AttributeName]Attribute) { | ||
|
@@ -373,3 +401,50 @@ | |
} | ||
return strings.TrimSpace(string(output)), nil | ||
} | ||
|
||
type featureGate struct { | ||
// Required. | ||
Id string `mapstructure:"id"` | ||
mx-psi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Description describes the purpose of the attribute. | ||
Description string `mapstructure:"description"` | ||
// Stage current stage at which the feature gate is in the development lifecyle | ||
Stage string `mapstructure:"stage"` | ||
// ReferenceURL can optionally give the url of the feature_gate | ||
ReferenceURL string `mapstructure:"reference_url"` | ||
// FromVersion optional field which gives the release version from which the gate has been given the current stage | ||
FromVersion string `mapstructure:"from_version"` | ||
// ToVersion optional field which gives the release version till which the gate the gate had the given lifecycle stage | ||
ToVersion string `mapstructure:"to_version"` | ||
// FeatureGateName name of the feature gate | ||
FeatureGateName featureGateName `mapstructure:"-"` | ||
} | ||
|
||
func (f *featureGate) validate(parser *confmap.Conf) error { | ||
if !parser.IsSet("id") { | ||
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. We should also check for stage, that is also a required field |
||
return errors.New("missing required field: `id`") | ||
} | ||
var err []error | ||
if !idRegexp.MatchString(fmt.Sprintf("%v", parser.Get("id"))) { | ||
err = append(err, fmt.Errorf("invalid character(s) in ID")) | ||
} | ||
if !versionRegexp.MatchString(fmt.Sprintf("%v", parser.Get("from_version"))) { | ||
err = append(err, fmt.Errorf("invalid character(s) in from_version")) | ||
} | ||
if !versionRegexp.MatchString(fmt.Sprintf("%v", parser.Get("to_version"))) { | ||
err = append(err, fmt.Errorf("invalid character(s) in to_version")) | ||
} | ||
if !referenceURLRegexp.MatchString(fmt.Sprintf("%v", parser.Get("reference_url"))) { | ||
err = append(err, fmt.Errorf("invalid character(s) in reference_url")) | ||
} | ||
Comment on lines
+430
to
+438
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. All of these should check first where the field is set, otherwise they are effectively required, aren't they? For example, instead of: if !versionRegexp.MatchString(fmt.Sprintf("%v", parser.Get("from_version"))) {
err = append(err, fmt.Errorf("invalid character(s) in from_version"))
} we should do something similar to this if parser.IsSet("from_version") && !versionRegexp.MatchString(fmt.Sprintf("%v", parser.Get("from_version"))) {
err = append(err, fmt.Errorf("invalid character(s) in from_version"))
} |
||
if _, ok := validStages[fmt.Sprintf("%v", parser.Get("stage"))]; !ok { | ||
err = append(err, fmt.Errorf("invalid stage")) | ||
} | ||
return errors.Join(err...) | ||
} | ||
|
||
func (f *featureGate) Unmarshal(parser *confmap.Conf) error { | ||
if err := f.validate(parser); err != nil { | ||
return err | ||
} | ||
return parser.Unmarshal(f) | ||
} |
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.
We are missing the code generation! We need to generate something like this:
opentelemetry-collector/featuregate/README.md
Lines 19 to 25 in 388bae7