From 5f27d193b43fd606b99f6b41198881b8768e6afd Mon Sep 17 00:00:00 2001 From: Samantha Coyle Date: Wed, 18 Dec 2024 17:18:19 -0600 Subject: [PATCH] refactor: use build tags with generator instead Signed-off-by: Samantha Coyle --- .../builtin-authentication-profiles.yaml | 60 +- .../cmd/cmd-bundle-component-metadata.go | 4 +- .../cmd-gen-component-metadata-ast-mocks.go | 147 ++++ .../cmd/cmd-gen-component-metadata-helpers.go | 675 +++++++++++++++++ ...cmd-gen-component-metadata-helpers_test.go | 677 ++++++++++++++++++ .../cmd/cmd-gen-component-metadata.go | 677 ++---------------- .build-tools/go.mod | 112 +-- .build-tools/go.sum | 297 +------- Makefile | 2 +- bindings/apns/apns.go | 12 +- bindings/apns/metadata.go | 58 +- bindings/aws/dynamodb/metadata.go | 27 +- bindings/aws/s3/metadata.go | 54 +- bindings/azure/blobstorage/blobstorage.go | 2 + common/component/interface.go | 9 + 15 files changed, 1727 insertions(+), 1086 deletions(-) create mode 100644 .build-tools/cmd/cmd-gen-component-metadata-ast-mocks.go create mode 100644 .build-tools/cmd/cmd-gen-component-metadata-helpers.go create mode 100644 .build-tools/cmd/cmd-gen-component-metadata-helpers_test.go create mode 100644 common/component/interface.go diff --git a/.build-tools/builtin-authentication-profiles.yaml b/.build-tools/builtin-authentication-profiles.yaml index 0bd9548bda..ba553aa9f7 100644 --- a/.build-tools/builtin-authentication-profiles.yaml +++ b/.build-tools/builtin-authentication-profiles.yaml @@ -9,7 +9,7 @@ aws: description: | The AWS Region where the AWS resource is deployed to. This will be marked required in Dapr 1.17. - example: '"us-east-1"' + example: us-east-1 - name: awsRegion type: string required: false @@ -17,17 +17,17 @@ aws: This maintains backwards compatibility with existing fields. It will be deprecated as of Dapr 1.17. Use 'region' instead. The AWS Region where the AWS resource is deployed to. - example: '"us-east-1"' + example: us-east-1 - name: accessKey description: AWS access key associated with an IAM account required: false sensitive: true - example: '"AKIAIOSFODNN7EXAMPLE"' + example: AKIAIOSFODNN7EXAMPLE - name: secretKey description: The secret key associated with the access key required: false sensitive: true - example: '"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"' + example: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY - name: sessionToken type: string required: false @@ -35,7 +35,7 @@ aws: description: | AWS session token to use. A session token is only required if you are using temporary security credentials. - example: '"TOKEN"' + example: TOKEN - title: "AWS: Assume IAM Role" description: | Assume a specific IAM role. Note: This is only supported for Kafka and PostgreSQL. @@ -45,7 +45,7 @@ aws: required: true description: | The AWS Region where the AWS resource is deployed to. - example: '"us-east-1"' + example: us-east-1 - name: assumeRoleArn type: string required: false @@ -53,13 +53,13 @@ aws: IAM role that has access to AWS resource. This is another option to authenticate with MSK and RDS Aurora aside from the AWS Credentials. This will be marked required in Dapr 1.17. - example: '"arn:aws:iam::123456789:role/mskRole"' + example: arn:aws:iam::123456789:role/mskRole - name: sessionName type: string description: | The session name for assuming a role. - example: '"MyAppSession"' - default: '"DaprDefaultSession"' + example: MyAppSession + default: DaprDefaultSession - title: "AWS: Credentials from Environment Variables" description: Use AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from the environment - title: "AWS: IAM Roles Anywhere" @@ -88,12 +88,12 @@ azuread: - name: azureClientId description: | Client ID (application ID). Required if the service has multiple identities assigned. - example: '"c7dd251f-811f-4ba2-a905-acd4d3f8f08b"' + example: c7dd251f-811f-4ba2-a905-acd4d3f8f08b - name: azureEnvironment description: | Optional name for the Azure environment if using a different Azure cloud default: AzurePublicCloud - example: '"AzurePublicCloud"' + example: AzurePublicCloud allowedValues: - AzurePublicCloud - AzureChinaCloud @@ -105,21 +105,21 @@ azuread: - name: azureTenantId description: ID of the Azure AD tenant required: true - example: '"cd4b2887-304c-47e1-b4d5-65447fdd542a"' + example: cd4b2887-304c-47e1-b4d5-65447fdd542a - name: azureClientId description: Client ID (application ID) required: true - example: '"c7dd251f-811f-4ba2-a905-acd4d3f8f08b"' + example: c7dd251f-811f-4ba2-a905-acd4d3f8f08b - name: azureClientSecret description: Client secret (application password) required: true sensitive: true - example: '"Ecy3XG7zVZK3/vl/a2NSB+a1zXLa8RnMum/IgD0E"' + example: Ecy3XG7zVZK3/vl/a2NSB+a1zXLa8RnMum/IgD0E - name: azureEnvironment description: | Optional name for the Azure environment if using a different Azure cloud default: AzurePublicCloud - example: '"AzurePublicCloud"' + example: AzurePublicCloud allowedValues: - AzurePublicCloud - AzureChinaCloud @@ -131,11 +131,11 @@ azuread: - name: azureTenantId description: ID of the Azure AD tenant required: true - example: '"cd4b2887-304c-47e1-b4d5-65447fdd542a"' + example: cd4b2887-304c-47e1-b4d5-65447fdd542a - name: azureClientId description: Client ID (application ID) required: true - example: '"c7dd251f-811f-4ba2-a905-acd4d3f8f08b"' + example: c7dd251f-811f-4ba2-a905-acd4d3f8f08b - name: azureCertificate description: | Certificate and private key (in either a PEM file containing both the certificate and key, or in PFX/PKCS#12 format) @@ -146,16 +146,16 @@ azuread: - name: azureCertificateFile description: | Path to PEM or PFX/PKCS#12 file on disk, containing the certificate and private key. - example: '"/path/to/file.pem"' + example: /path/to/file.pem - name: azureCertificatePassword description: Password for the certificate if encrypted. sensitive: true - example: '"password"' + example: password - name: azureEnvironment description: | Optional name for the Azure environment if using a different Azure cloud default: AzurePublicCloud - example: '"AzurePublicCloud"' + example: AzurePublicCloud allowedValues: - AzurePublicCloud - AzureChinaCloud @@ -171,19 +171,19 @@ gcp: sensitive: true description: | The GCP private key id. Replace with the value of "private_key_id" field of the Service Account Key file. - example: '"privateKeyID"' + example: privateKeyID - name: privateKey required: true sensitive: true description: | The GCP credentials private key. Replace with the value of "private_key" field of the Service Account Key file. - example: '"-----BEGIN PRIVATE KEY-----\nMIIE...\\n-----END PRIVATE KEY-----\n"' + example: -----BEGIN PRIVATE KEY-----\nMIIE...\\n-----END PRIVATE KEY-----\n - name: type type: string required: false description: | The GCP credentials type. - example: '"service_account"' + example: service_account allowedValues: - service_account - name: projectID @@ -191,41 +191,41 @@ gcp: required: true description: | GCP project id. - example: '"projectID"' + example: projectID - name: clientEmail type: string required: true description: | GCP client email. - example: '"client@email.com"' + example: client@email.com - name: clientID type: string required: true description: | The GCP client ID. - example: '"0123456789-0123456789"' + example: 0123456789-0123456789 - name: authURI type: string required: false description: | The GCP account OAuth2 authorization server endpoint URI. - example: '"https://accounts.google.com/o/oauth2/auth"' + example: https://accounts.google.com/o/oauth2/auth - name: tokenURI type: string required: false description: | The GCP account token server endpoint URI. - example: '"https://oauth2.googleapis.com/token"' + example: https://oauth2.googleapis.com/token - name: authProviderX509CertURL type: string required: false description: | The GCP URL of the public x509 certificate, used to verify the signature on JWTs, such as ID tokens, signed by the authentication provider. - example: '"https://www.googleapis.com/oauth2/v1/certs"' + example: https://www.googleapis.com/oauth2/v1/certs - name: clientX509CertURL type: string required: false description: | The GCP URL of the public x509 certificate, used to verify JWTs signed by the client. - example: '"https://www.googleapis.com/robot/v1/metadata/x509/.iam.gserviceaccount.com"' + example: https://www.googleapis.com/robot/v1/metadata/x509/.iam.gserviceaccount.com diff --git a/.build-tools/cmd/cmd-bundle-component-metadata.go b/.build-tools/cmd/cmd-bundle-component-metadata.go index 8bc1153329..46019f70c4 100644 --- a/.build-tools/cmd/cmd-bundle-component-metadata.go +++ b/.build-tools/cmd/cmd-bundle-component-metadata.go @@ -56,8 +56,8 @@ var bundleComponentMetadataCmd = &cobra.Command{ Components: make([]*metadataschema.ComponentMetadata, 0, len(list)), } for _, component := range list { - componentMetadata, err := parser.LoadForComponent(component) - if err != nil { + componentMetadata, loadErr := parser.LoadForComponent(component) + if loadErr != nil { panic(fmt.Errorf("failed to load metadata for component %s: %w", component, err)) } if componentMetadata == nil { diff --git a/.build-tools/cmd/cmd-gen-component-metadata-ast-mocks.go b/.build-tools/cmd/cmd-gen-component-metadata-ast-mocks.go new file mode 100644 index 0000000000..1eedf46ecb --- /dev/null +++ b/.build-tools/cmd/cmd-gen-component-metadata-ast-mocks.go @@ -0,0 +1,147 @@ +/* +Copyright 2024 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "go/ast" + "go/token" +) + +func createMockASTFileWithFunc(funcName string, found bool) *ast.File { + if !found { + return &ast.File{} + } + // Create a mock AST with the specified function name + return &ast.File{ + Decls: []ast.Decl{ + &ast.FuncDecl{ + Name: &ast.Ident{Name: funcName}, + Body: createValidFunctionBody(), + }, + }, + } +} + +func createValidFunctionBody() *ast.BlockStmt { + return &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ReturnStmt{ + Results: []ast.Expr{createValidCompositeLit()}, + }, + }, + } +} + +func createValidCompositeLit() *ast.CompositeLit { + return &ast.CompositeLit{ + // Using SelectorExpr for the type field to match 'Binding' type + Type: &ast.SelectorExpr{ + X: &ast.Ident{Name: "metadataschema"}, // Package name + Sel: &ast.Ident{Name: "Binding"}, // Type name + }, + Elts: []ast.Expr{ + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "Input"}, + Value: &ast.Ident{Name: "true"}, // Keep it as an Ident (literal bool type) + }, + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "Output"}, + Value: &ast.Ident{Name: "false"}, // Keep it as an Ident (literal bool type) + }, + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "Operations"}, + Value: &ast.CompositeLit{ + Elts: []ast.Expr{ + &ast.CompositeLit{ + Elts: []ast.Expr{ + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "Name"}, + Value: &ast.BasicLit{Kind: token.STRING, Value: `"create"`}, // Correct string literal + }, + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "Description"}, + Value: &ast.BasicLit{Kind: token.STRING, Value: `"Create blob"`}, // Correct string literal + }, + }, + }, + &ast.CompositeLit{ + Elts: []ast.Expr{ + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "Name"}, + Value: &ast.BasicLit{Kind: token.STRING, Value: `"get"`}, // Correct string literal + }, + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "Description"}, + Value: &ast.BasicLit{Kind: token.STRING, Value: `"Get blob"`}, // Correct string literal + }, + }, + }, + }, + }, + }, + }, + } +} + +func createInvalidCompositeLit() *ast.CompositeLit { + return &ast.CompositeLit{ + Type: &ast.Ident{Name: "NotBinding"}, + Elts: []ast.Expr{ + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "InvalidInput"}, + Value: &ast.Ident{Name: "true"}, + }, + &ast.KeyValueExpr{ + Key: &ast.Ident{Name: "InvalidOutput"}, + Value: &ast.Ident{Name: "false"}, + }, + }, + } +} + +func createKeyValueExpr(key, value string) *ast.KeyValueExpr { + return &ast.KeyValueExpr{ + Key: &ast.Ident{Name: key}, + Value: &ast.BasicLit{Kind: token.STRING, Value: value}, + } +} + +func createInvalidKeyValueExpr(value string) *ast.KeyValueExpr { + return &ast.KeyValueExpr{ + Key: nil, // this is invalid intentionally and should actually be &ast.Ident{Name: key}, + Value: &ast.Ident{Name: value}, + } +} + +func createBodyWithoutBindingReturn() *ast.BlockStmt { + return &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ReturnStmt{ + Results: []ast.Expr{ + // createNonBindingReturn(), + }, + }, + }, + } +} + +// Helper function to create a CompositeLit for a single BindingOperation +func createBindingOperationCompositeLit(name, description string) *ast.CompositeLit { + return &ast.CompositeLit{ + Elts: []ast.Expr{ + createKeyValueExpr("Name", name), + createKeyValueExpr("Description", description), + }, + } +} diff --git a/.build-tools/cmd/cmd-gen-component-metadata-helpers.go b/.build-tools/cmd/cmd-gen-component-metadata-helpers.go new file mode 100644 index 0000000000..969006f19b --- /dev/null +++ b/.build-tools/cmd/cmd-gen-component-metadata-helpers.go @@ -0,0 +1,675 @@ +/* +Copyright 2024 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "errors" + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "strings" + + "github.com/spf13/cobra" + "gopkg.in/yaml.v3" + + "github.com/dapr/components-contrib/build-tools/pkg/metadataschema" +) + +type cliFlags struct { + componentType string + builtinAuth []string + status string + version string + direction string + origin string + title string +} + +// Helper function to fetch command flags +func getCmdFlags(cmd *cobra.Command) *cliFlags { + componentType, _ := cmd.Flags().GetString("type") + builtinAuth, _ := cmd.Flags().GetStringSlice("builtinAuth") + status, _ := cmd.Flags().GetString("status") + version, _ := cmd.Flags().GetString("version") + direction, _ := cmd.Flags().GetString("direction") + origin, _ := cmd.Flags().GetString("origin") + title, _ := cmd.Flags().GetString("title") + + return &cliFlags{ + componentType: componentType, + builtinAuth: builtinAuth, + status: status, + version: version, + direction: direction, + origin: origin, + title: title, + } +} + +// Helper function to get component name based on origin +func getComponentName(origin, pkg string) string { + const ( + awsPrefix = "aws" + azurePrefix = "azure" + gcpPrefix = "gcp" + ) + + switch { + case strings.Contains(origin, awsPrefix): + return awsPrefix + "." + pkg + case strings.Contains(origin, azurePrefix): + return azurePrefix + "." + pkg + case strings.Contains(origin, gcpPrefix): + return gcpPrefix + "." + pkg + default: + return pkg + } +} + +func assembleComponentMetadata(flags *cliFlags, componentName string, metadata []metadataschema.Metadata, bindingSpec metadataschema.Binding) (metadataschema.ComponentMetadata, error) { + component := metadataschema.ComponentMetadata{ + SchemaVersion: "v2", + Type: flags.componentType, + Name: componentName, + Version: flags.version, + Status: flags.status, + Title: flags.title, + Metadata: metadata, + URLs: supportedComponentURL(flags.componentType, componentName), + Binding: &bindingSpec, + } + + if len(flags.builtinAuth) > 0 { + addBuiltinAuthProfiles(flags.builtinAuth, &component) + } + + if err := component.AppendBuiltin(); err != nil { + return metadataschema.ComponentMetadata{}, fmt.Errorf("Error appending built-in metadata: %v", err) + } + return component, nil +} + +func addBuiltinAuthProfiles(authProfiles []string, component *metadataschema.ComponentMetadata) { + allBuiltinProfiles := []metadataschema.BuiltinAuthenticationProfile{ + {Name: "aws"}, + {Name: "azuread"}, + {Name: "gcp"}, + } + + for _, compProfiles := range authProfiles { + for _, options := range allBuiltinProfiles { + if strings.EqualFold(compProfiles, options.Name) { + component.BuiltInAuthenticationProfiles = append(component.BuiltInAuthenticationProfiles, options) + } + } + } +} + +// TODO: add test +// generateComponentOperations reads the Go file and extracts the s3Operations variable as a Binding type. +func generateComponentOperations(filePath, funcName string) (*metadataschema.Binding, error) { + node, err := parseGoFile(filePath) + if err != nil { + return nil, err + } + + // Search for the specified function and extract its binding + return findBindingInFunction(node, funcName) +} + +// findBindingInFunction searches for a specific function and extracts a Binding struct from its return statement +func findBindingInFunction(node *ast.File, funcName string) (*metadataschema.Binding, error) { + for _, decl := range node.Decls { + funcDecl, ok := decl.(*ast.FuncDecl) + if !ok || funcDecl.Name.Name != funcName { + continue + } + + return extractBindingFromFunctionBody(funcDecl.Body) + } + + return nil, fmt.Errorf("function %s not found", funcName) +} + +// extractBindingFromFunctionBody processes the body of a function to find and construct a Binding struct +func extractBindingFromFunctionBody(body *ast.BlockStmt) (*metadataschema.Binding, error) { + if body == nil || len(body.List) == 0 { + return nil, errors.New("function body is empty") + } + + for _, stmt := range body.List { + retStmt, ok := stmt.(*ast.ReturnStmt) + if !ok || len(retStmt.Results) != 1 { + continue + } + + binding, err := parseBindingStruct(retStmt.Results[0]) + if err != nil { + return nil, err + } + + return binding, nil + } + + return nil, errors.New("no return statement with a Binding found") +} + +// parseBindingStruct parses a CompositeLit expression into a Binding struct +func parseBindingStruct(expr ast.Expr) (*metadataschema.Binding, error) { + structLit, ok := expr.(*ast.CompositeLit) + if !ok { + return nil, errors.New("return value is not a composite literal") + } + + // Check if the type of the composite literal is "Binding" type + // Note: the underlying structLit.Type is &{metadataschema Binding} which is pkg and then actual type + // So, we must do this below to account for. + /* + Type: &ast.SelectorExpr{ + X: &ast.Ident{Name: "metadataschema"}, // Package name + Sel: &ast.Ident{Name: "Binding"}, // Type name + }, + */ + if ident, ok := structLit.Type.(*ast.SelectorExpr); !ok || ident.Sel.Name != "Binding" { + return nil, errors.New("return value is not a composite literal of type Binding") + } + binding := &metadataschema.Binding{} + for _, elt := range structLit.Elts { + if kv, ok := elt.(*ast.KeyValueExpr); ok { + if err := populateBindingField(binding, kv); err != nil { + return nil, err + } + } + } + return binding, nil +} + +func populateBindingField(binding *metadataschema.Binding, kv *ast.KeyValueExpr) error { + key, ok := kv.Key.(*ast.Ident) + if !ok { + return errors.New("key is not an identifier") + } + + switch key.Name { + case "Input": + binding.Input = parseBoolValue(kv.Value) + case "Output": + binding.Output = parseBoolValue(kv.Value) + case "Operations": + // Parse the operations array + operations, err := parseOperationsArray(kv.Value) + if err != nil { + return err + } + binding.Operations = operations + } + + return nil +} + +// parseBoolValue parses a boolean value from an AST node +func parseBoolValue(value ast.Expr) bool { + ident, ok := value.(*ast.Ident) + if !ok { + return false + } + return ident.Name == "true" +} + +// parseOperationsArray parses the operations array and returns a slice of BindingOperation +func parseOperationsArray(value ast.Expr) ([]metadataschema.BindingOperation, error) { + // Ensure the value is a CompositeLit + compLit, ok := value.(*ast.CompositeLit) + if !ok { + return nil, errors.New("operations field is not a composite literal") + } + var operations []metadataschema.BindingOperation + for _, elt := range compLit.Elts { + // Each element in the operations array is a CompositeLit + operationLit, ok := elt.(*ast.CompositeLit) + if !ok { + return nil, errors.New("expected CompositeLit for BindingOperation") + } + + operation := metadataschema.BindingOperation{} + for _, opElt := range operationLit.Elts { + // Each element inside the operation is a KeyValueExpr (Name, Description) + if kv, ok := opElt.(*ast.KeyValueExpr); ok { + // Extract Name and Description from the KeyValueExpr + // Check the keys and extract the correct values + if kv.Key.(*ast.Ident).Name == "Name" { + operation.Name = extractStringValue(kv.Value) + } + if kv.Key.(*ast.Ident).Name == "Description" { + operation.Description = extractStringValue(kv.Value) + } + } + } + + // validate Name and Description fields as both must be present + if err := validateOperationFields(operation); err != nil { + return nil, err + } + + operations = append(operations, operation) + } + + return operations, nil +} + +// validateOperationFields checks if both Name and Description are populated. +func validateOperationFields(op metadataschema.BindingOperation) error { + if op.Name == "" { + return errors.New("missing 'Name' field in BindingOperation") + } + if op.Description == "" { + return errors.New("missing 'Description' field in BindingOperation") + } + return nil +} + +// extractStringValue extracts a string literal value +func extractStringValue(expr ast.Expr) string { + if strLit, ok := expr.(*ast.BasicLit); ok { + return strings.Trim(strLit.Value, `"`) + } + return "" +} + +func writeToFile(outputFilePath string, component metadataschema.ComponentMetadata) error { + // Open the file for writing (create if not exists) + file, err := os.Create(outputFilePath) + if err != nil { + return fmt.Errorf("could not create file: %v", err) + } + defer file.Close() + + // update the field names to lowercase + for i := range component.Metadata { + component.Metadata[i].Name = lowercaseFirstLetter(component.Metadata[i].Name) + } + + yamlEncoder := yaml.NewEncoder(file) + yamlEncoder.SetIndent(2) + if err := yamlEncoder.Encode(&component); err != nil { + return fmt.Errorf("error encoding YAML: %w", err) + } + + return nil +} + +func checkFileExists(filePath string) { + _, err := os.Stat(filePath) + if err != nil { + if os.IsNotExist(err) { + fmt.Printf("File does not exist: %s\n", filePath) + } else { + fmt.Printf("Error checking file: %v\n", err) + } + return + } +} + +func parseJSONTag(tag string) string { + // Remove the backticks and split the tag + tag = strings.Trim(tag, "`") + parts := strings.Split(tag, " ") + for _, part := range parts { + if strings.HasPrefix(part, "json:") { + // Extract the json field name and remove any options like "omitempty" + jsonTag := part[len("json:"):] + jsonTag = strings.Trim(jsonTag, `"`) // Remove surrounding quotes + if commaIdx := strings.Index(jsonTag, ","); commaIdx != -1 { + jsonTag = jsonTag[:commaIdx] + } + return jsonTag + } + } + return "" +} + +type FieldInfo struct { + Name string + JSONTag string + Description string + Required bool + Sensitive bool + Type string + Default string + Example string + AllowedValues []string + Binding *metadataschema.MetadataBinding + Deprecated bool + AuthenticationProfileKey string +} + +// generateMetadataFromStructs processes a Go struct to extract metadata and authentication profile data. +func generateMetadataFromStructs(filePath, structName, underlyingComponentName string) ([]metadataschema.Metadata, map[string][]metadataschema.Metadata, error) { + src, err := os.ReadFile(filePath) + if err != nil { + return nil, nil, fmt.Errorf("failed to read file: %w", err) + } + + // Parse the Go source file + fset := token.NewFileSet() + node, err := parser.ParseFile(fset, filePath, src, parser.AllErrors|parser.ParseComments) + if err != nil { + return nil, nil, fmt.Errorf("failed to parse Go file: %w", err) + } + + // Extract metadata and authentication profiles + metadataEntries, authProfileMetadataMap := extractMetadataFromAST(node, structName, filePath, underlyingComponentName) + return metadataEntries, authProfileMetadataMap, nil +} + +// extractMetadataFromAST traverses the AST to locate the struct and extract metadata. +func extractMetadataFromAST(node *ast.File, structName, filePath, underlyingComponentName string) ([]metadataschema.Metadata, map[string][]metadataschema.Metadata) { + var metadataEntries []metadataschema.Metadata + authProfileMetadataMap := make(map[string][]metadataschema.Metadata) + + for _, decl := range node.Decls { + genDecl, ok := decl.(*ast.GenDecl) + if !ok || genDecl.Tok != token.TYPE { + continue + } + + for _, spec := range genDecl.Specs { + typeSpec, ok := spec.(*ast.TypeSpec) + if !ok || typeSpec.Name.Name != structName { + continue + } + + structType, ok := typeSpec.Type.(*ast.StructType) + if !ok { + continue + } + + // Process each field in the struct + for _, field := range structType.Fields.List { + fieldInfo := extractFieldInfo(filePath, field, underlyingComponentName) + if fieldInfo == nil { + continue + } + + metadata := convertFieldInfoToMetadata(fieldInfo) + if fieldInfo.AuthenticationProfileKey != "" { + authProfileMetadataMap[fieldInfo.AuthenticationProfileKey] = append(authProfileMetadataMap[fieldInfo.AuthenticationProfileKey], metadata) + } else { + metadataEntries = append(metadataEntries, metadata) + } + } + } + } + + return metadataEntries, authProfileMetadataMap +} + +// convertFieldInfoToMetadata converts a FieldInfo object into a Metadata object. +func convertFieldInfoToMetadata(fieldInfo *FieldInfo) metadataschema.Metadata { + return metadataschema.Metadata{ + Name: fieldInfo.JSONTag, + Description: fieldInfo.Description, + Required: fieldInfo.Required, + Sensitive: fieldInfo.Sensitive, + Type: fieldInfo.Type, + Default: fieldInfo.Default, + Example: fieldInfo.Example, + AllowedValues: fieldInfo.AllowedValues, + Binding: fieldInfo.Binding, + Deprecated: fieldInfo.Deprecated, + } +} + +// parseAuthProfileTag extracts the authentication profile key from a struct tag. +func parseAuthProfileTag(tag string) string { + tagParts := strings.Split(tag, " ") + for _, part := range tagParts { + if strings.HasPrefix(part, "authenticationProfile:") { + return strings.Trim(part[len("authenticationProfile:"):], "\"`") + } + } + return "" +} + +// extractFieldInfo extracts metadata for a struct field. +func extractFieldInfo(filePath string, field *ast.Field, componentName string) *FieldInfo { + if len(field.Names) == 0 { + return nil + } + + fieldName := field.Names[0].Name + fieldType := fmt.Sprintf("%s", field.Type) + + // Extract comments + description := extractFieldDescription(field) + + // Extract JSON tag and metadata + jsonTag, required, authProfileKey, bindingsMeta := extractTags(field.Tag) + + // Ignore fields based on specific tags + if shouldIgnoreField(field.Tag) { + return nil + } + + // Populate and return FieldInfo + return &FieldInfo{ + Name: fieldName, + JSONTag: jsonTag, + Description: description, + Required: required, + Sensitive: isFieldSensitive(fieldName), + Type: fieldType, + Default: getFunctionValueForField(filePath, componentName, fieldName, "Defaults"), + Example: getFunctionValueForField(filePath, componentName, fieldName, "Examples"), + AllowedValues: []string{}, // TODO: Populate as needed + Binding: &bindingsMeta, + Deprecated: false, + AuthenticationProfileKey: strings.TrimSpace(strings.ToLower(authProfileKey)), + } +} + +// extractFieldDescription extracts the description for a field from its comments or documentation. +func extractFieldDescription(field *ast.Field) string { + if field.Comment != nil { + return strings.TrimSpace(field.Comment.Text()) + } + if field.Doc != nil { + return strings.TrimSpace(field.Doc.Text()) + } + return "" +} + +// extractTags parses the field's tags to extract JSON tag, required status, authentication profile key, and bindings metadata. +func extractTags(tag *ast.BasicLit) (jsonTag string, required bool, authProfileKey string, bindingsMeta metadataschema.MetadataBinding) { + if tag == nil { + return "", true, "", metadataschema.MetadataBinding{} + } + + tagValue := tag.Value + jsonTag = parseJSONTag(tagValue) + + // Determine if the field is required + required = !strings.Contains(tagValue, "omitempty") + + // Extract authentication profile key and bindings metadata + authProfileKey = parseAuthProfileTag(tagValue) + bindingsMeta = extractBindingMetadata(tagValue) + + return jsonTag, required, authProfileKey, bindingsMeta +} + +// shouldIgnoreField determines whether a field should be ignored based on specific tags. +func shouldIgnoreField(tag *ast.BasicLit) bool { + if tag == nil { + return false + } + + tagValue := tag.Value + return strings.Contains(tagValue, "mdignore") || strings.Contains(tagValue, `mapstructure:"-"`) +} + +// extractBindingMetadata parses the binding metadata from a field tag. +func extractBindingMetadata(tagValue string) metadataschema.MetadataBinding { + bindingsMeta := metadataschema.MetadataBinding{} + + if strings.Contains(tagValue, `binding:"input"`) { + bindingsMeta.Input = true + } + if strings.Contains(tagValue, `binding:"output"`) { + bindingsMeta.Output = true + } + + return bindingsMeta +} + +// isFieldSensitive determines if a field name indicates that the field contains sensitive information. +func isFieldSensitive(field string) bool { + fieldLower := strings.ToLower(field) + return strings.Contains(fieldLower, "key") || strings.Contains(fieldLower, "token") +} + +// isPointerReceiver checks if a function's receiver is a pointer type. +func isPointerReceiver(fn *ast.FuncDecl) bool { + if fn.Recv == nil || len(fn.Recv.List) == 0 { + return false + } + // Check if the receiver is a pointer type + _, isPointer := fn.Recv.List[0].Type.(*ast.StarExpr) + return isPointer +} + +// getFunctionValueForField retrieves the value of a specific field returned by a given function in a Go file. +func getFunctionValueForField(filePath, componentName, fieldName, functionName string) string { + // Parse the Go file + node, err := parseGoFile(filePath) + if err != nil { + fmt.Printf("Failed to parse file: %v\n", err) + return "" + } + + // Find the target function with a pointer receiver + functionNode := findFunctionByName(node, functionName) + if functionNode == nil { + return functionName + " function not found" + } + + // Extract the return statement + returnStmt := findReturnStatement(functionNode) + if returnStmt == nil { + return "No return statement found in " + functionName + } + + // Retrieve the field value from the return statement + return extractFieldValueFromReturn(returnStmt, fieldName) +} + +// parseGoFile parses a Go source file and returns the root node. +func parseGoFile(filePath string) (*ast.File, error) { + fs := token.NewFileSet() + return parser.ParseFile(fs, filePath, nil, parser.AllErrors) +} + +// findFunctionByName locates a function declaration by its name and checks for a pointer receiver. +func findFunctionByName(node *ast.File, functionName string) *ast.FuncDecl { + var targetFunc *ast.FuncDecl + ast.Inspect(node, func(n ast.Node) bool { + if fn, ok := n.(*ast.FuncDecl); ok && fn.Name.Name == functionName && isPointerReceiver(fn) { + targetFunc = fn + return false // Stop traversal once found + } + return true + }) + return targetFunc +} + +// findReturnStatement locates the first return statement in a function body. +func findReturnStatement(fn *ast.FuncDecl) *ast.ReturnStmt { + var returnStmt *ast.ReturnStmt + ast.Inspect(fn.Body, func(n ast.Node) bool { + if stmt, ok := n.(*ast.ReturnStmt); ok { + returnStmt = stmt + return false // Stop traversal once found + } + return true + }) + return returnStmt +} + +// extractFieldValueFromReturn extracts the value of a specific field from a return statement. +func extractFieldValueFromReturn(returnStmt *ast.ReturnStmt, fieldName string) string { + for _, result := range returnStmt.Results { + if structLit, ok := result.(*ast.CompositeLit); ok { + for _, elt := range structLit.Elts { + if kv, ok := elt.(*ast.KeyValueExpr); ok { + if key, ok := kv.Key.(*ast.Ident); ok && strings.EqualFold(key.Name, fieldName) { + return parseFieldValue(kv.Value) + } + } + } + } + } + return "" +} + +// parseFieldValue parses a field value and returns it as a string. +func parseFieldValue(value ast.Expr) string { + switch v := value.(type) { + case *ast.BasicLit: + return parseBasicLiteral(v) + case *ast.Ident: + return v.Name // For booleans or other identifiers + default: + return "" + } +} + +// parseBasicLiteral parses a basic literal and returns its value as a string. +func parseBasicLiteral(value *ast.BasicLit) string { + switch value.Kind { + case token.STRING: + return strings.Trim(value.Value, `'"`) + case token.INT, token.FLOAT: + return value.Value + default: + return value.Value + } +} + +// lowercaseFirstLetter lowercases the first letter of a string +func lowercaseFirstLetter(s string) string { + if len(s) == 0 { + return s + } + return strings.ToLower(string(s[0])) + s[1:] +} + +func supportedComponentURL(componentType, componentName string) []metadataschema.URL { + referenceURLs := map[string]string{ + "bindings": "bindings", + "state": "state-stores", + "secretstores": "secret-stores", + "TODO": "conversation", + "pubsub": "pubsub", + } + var urls []metadataschema.URL + urls = append(urls, metadataschema.URL{ + Title: "Reference", + URL: fmt.Sprintf("https://docs.dapr.io/reference/components-reference/supported-%s/%s/", + referenceURLs[componentType], componentName), + }) + + return urls +} diff --git a/.build-tools/cmd/cmd-gen-component-metadata-helpers_test.go b/.build-tools/cmd/cmd-gen-component-metadata-helpers_test.go new file mode 100644 index 0000000000..0b353f0c55 --- /dev/null +++ b/.build-tools/cmd/cmd-gen-component-metadata-helpers_test.go @@ -0,0 +1,677 @@ +/* +Copyright 2024 The Dapr Authors +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "errors" + "go/ast" + "go/token" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/dapr/components-contrib/build-tools/pkg/metadataschema" +) + +func TestGetCmdFlags(t *testing.T) { + tests := []struct { + name string + flags map[string]interface{} + expectedResult *cliFlags + }{ + { + name: "All flags set", + flags: map[string]interface{}{ + "type": "state", + "builtinAuth": []string{"auth1", "auth2"}, + "status": "stable", + "version": "v1", + "direction": "input", + "origin": "/bindings/aws/s3", + "title": "Test Title", + }, + expectedResult: &cliFlags{ + componentType: "state", + builtinAuth: []string{"auth1", "auth2"}, + status: "stable", + version: "v1", + direction: "input", + origin: "/bindings/aws/s3", + title: "Test Title", + }, + }, + { + name: "Test missing flags", + flags: map[string]interface{}{ + "type": "pubsub", + }, + expectedResult: &cliFlags{ + componentType: "pubsub", + builtinAuth: []string{}, + status: "", + version: "", + direction: "", + origin: "", + title: "", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a new cobra command with flags + cmd := &cobra.Command{} + for flag, value := range tt.flags { + switch v := value.(type) { + case string: + cmd.Flags().String(flag, v, "") + case []string: + cmd.Flags().StringSlice(flag, v, "") + } + } + + result := getCmdFlags(cmd) + + // Assert the result + assert.Equal(t, tt.expectedResult, result) + }) + } +} + +func TestGetComponentName(t *testing.T) { + tests := []struct { + name string + origin string + pkg string + expectedResult string + }{ + { + name: "Test AWS component", + origin: "/bindings/aws/s3", + pkg: "s3", + expectedResult: "aws.s3", + }, + { + name: "Test Azure component", + origin: "/bindings/azure/blobstorage", + pkg: "blobstorage", + expectedResult: "azure.blobstorage", + }, + { + name: "Test GCP component", + origin: "pubsub/gcp/pubsub", + pkg: "pubsub", + expectedResult: "gcp.pubsub", + }, + { + name: "Test with no CSP in path", + origin: "", + pkg: "component", + expectedResult: "component", + }, + { + name: "Test with no CSP in path again", + origin: "/apns", + pkg: "apns", + expectedResult: "apns", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := getComponentName(tt.origin, tt.pkg) + assert.Equal(t, tt.expectedResult, result) + }) + } +} + +func TestAssembleComponentMetadata(t *testing.T) { + tests := []struct { + name string + flags *cliFlags + componentName string + metadata []metadataschema.Metadata + bindingSpec metadataschema.Binding + expectedResult metadataschema.ComponentMetadata + }{ + { + name: "Test with all fields set and builtinAuth", + flags: &cliFlags{ + componentType: "testType", + builtinAuth: []string{"aws", "azuread"}, + status: "stable", + version: "v1", + title: "Test title", + }, + componentName: "component1", + metadata: []metadataschema.Metadata{ + { + Name: "TestMetadataField", + Required: true, + Sensitive: false, + }, + }, + bindingSpec: metadataschema.Binding{ + Input: true, + Output: false, + Operations: []metadataschema.BindingOperation{ + { + Name: "completion", + Description: "Text completion", + }, + { + Name: "chat-completion", + Description: "Chat completion", + }, + }, + }, + expectedResult: metadataschema.ComponentMetadata{ + SchemaVersion: "v2", + Type: "testType", + Name: "component1", + Version: "v1", + Status: "stable", + Title: "Test title", + Metadata: []metadataschema.Metadata{ + { + Name: "TestMetadataField", + Required: true, + Sensitive: false, + }, + }, + URLs: supportedComponentURL("testType", "component1"), + Binding: &metadataschema.Binding{ + Input: true, + Output: false, + Operations: []metadataschema.BindingOperation{ + { + Name: "completion", + Description: "Text completion", + }, + { + Name: "chat-completion", + Description: "Chat completion", + }, + }, + }, + BuiltInAuthenticationProfiles: []metadataschema.BuiltinAuthenticationProfile{{Name: "aws", Metadata: []metadataschema.Metadata(nil)}, {Name: "azuread", Metadata: []metadataschema.Metadata(nil)}}, + }, + }, + { + name: "Test with missing builtinAuth", + flags: &cliFlags{ + componentType: "type2", + builtinAuth: nil, + status: "alpha", + version: "v2", + title: "Title2", + }, + componentName: "component2", + metadata: []metadataschema.Metadata{ + { + Name: "TestMetadataField", + Required: true, + Sensitive: false, + Type: "string", + Example: "test example", + Deprecated: false, + }, + }, + bindingSpec: metadataschema.Binding{ + Input: true, + Output: true, + Operations: []metadataschema.BindingOperation{ + { + Name: "completion", + Description: "Text completion", + }, + }, + }, + expectedResult: metadataschema.ComponentMetadata{ + SchemaVersion: "v2", + Type: "type2", + Name: "component2", + Version: "v2", + Status: "alpha", + Title: "Title2", + Metadata: []metadataschema.Metadata{ + { + Name: "TestMetadataField", + Required: true, + Sensitive: false, + Type: "string", + Example: "test example", + Deprecated: false, + }, + }, + URLs: supportedComponentURL("type2", "component2"), + Binding: &metadataschema.Binding{ + Input: true, + Output: true, + Operations: []metadataschema.BindingOperation{ + { + Name: "completion", + Description: "Text completion", + }, + }, + }, + }, + }, + { + name: "Test with empty flags and metadata", + flags: &cliFlags{ + componentType: "", + builtinAuth: nil, + status: "", + version: "", + title: "", + }, + componentName: "component3", + metadata: nil, + bindingSpec: metadataschema.Binding{}, + expectedResult: metadataschema.ComponentMetadata{ + SchemaVersion: "v2", + Type: "", + Name: "component3", + Version: "", + Status: "", + Title: "", + Metadata: nil, + URLs: supportedComponentURL("", "component3"), + Binding: &metadataschema.Binding{}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := assembleComponentMetadata(tt.flags, tt.componentName, tt.metadata, tt.bindingSpec) + require.NoError(t, err) + assert.Equal(t, tt.expectedResult.SchemaVersion, result.SchemaVersion) + assert.Equal(t, tt.expectedResult.Version, result.Version) + assert.Equal(t, tt.expectedResult.Name, result.Name) + assert.Equal(t, tt.expectedResult.Type, result.Type) + assert.Equal(t, tt.expectedResult.Status, result.Status) + assert.Equal(t, tt.expectedResult.Title, result.Title) + assert.Equal(t, tt.expectedResult.Description, result.Description) + assert.Equal(t, tt.expectedResult.URLs, result.URLs) + assert.Equal(t, tt.expectedResult.Binding.Input, result.Binding.Input) + assert.Equal(t, tt.expectedResult.Binding.Output, result.Binding.Output) + assert.Equal(t, tt.expectedResult.Binding.Operations, result.Binding.Operations) + assert.Equal(t, tt.expectedResult.Capabilities, result.Capabilities) + assert.Equal(t, tt.expectedResult.AuthenticationProfiles, result.AuthenticationProfiles) + assert.Equal(t, tt.expectedResult.BuiltInAuthenticationProfiles, result.BuiltInAuthenticationProfiles) + assert.Equal(t, tt.expectedResult.Metadata, result.Metadata) + }) + } +} + +func TestAddBuiltinAuthProfiles(t *testing.T) { + tests := []struct { + name string + authProfiles []string + expectedProfiles []metadataschema.BuiltinAuthenticationProfile + }{ + { + name: "Valid auth profiles", + authProfiles: []string{"aws", "azuread", "gcp"}, + expectedProfiles: []metadataschema.BuiltinAuthenticationProfile{{Name: "aws"}, {Name: "azuread"}, {Name: "gcp"}}, + }, + { + name: "Mixed case auth profiles", + authProfiles: []string{"Aws", "AZUREAD", "Gcp"}, + expectedProfiles: []metadataschema.BuiltinAuthenticationProfile{{Name: "aws"}, {Name: "azuread"}, {Name: "gcp"}}, + }, + { + name: "Non-existent profiles", + authProfiles: []string{"ldap", "saml"}, + expectedProfiles: []metadataschema.BuiltinAuthenticationProfile{}, + }, + { + name: "Some valid and some non-existent profiles", + authProfiles: []string{"aws", "ldap", "gcp"}, + expectedProfiles: []metadataschema.BuiltinAuthenticationProfile{{Name: "aws"}, {Name: "gcp"}}, + }, + { + name: "Empty auth profiles", + authProfiles: []string{}, + expectedProfiles: []metadataschema.BuiltinAuthenticationProfile{}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + component := &metadataschema.ComponentMetadata{} + addBuiltinAuthProfiles(tt.authProfiles, component) + assert.ElementsMatch(t, tt.expectedProfiles, component.BuiltInAuthenticationProfiles) + }) + } +} + +// TODO: add test for writeMetadataToFile + +// TODO: add test for generateComponentOperations + +func TestFindBindingInFunction(t *testing.T) { + tests := []struct { + name string + node *ast.File + funcName string + expectedBinding *metadataschema.Binding + expectedError error + }{ + { + name: "Test function found with binding", + funcName: "Binding", + node: createMockASTFileWithFunc("Binding", true), + expectedBinding: &metadataschema.Binding{ + Input: true, + Output: false, + Operations: []metadataschema.BindingOperation{ + metadataschema.BindingOperation{Name: "create", Description: "Create blob"}, + metadataschema.BindingOperation{Name: "get", Description: "Get blob"}, + }, + }, + expectedError: nil, + }, + { + name: "Test function Binding not found", + funcName: "Binding", + node: createMockASTFileWithFunc("Binding", false), + expectedBinding: nil, + expectedError: errors.New("function Binding not found"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + binding, err := findBindingInFunction(tt.node, tt.funcName) + assert.Equal(t, tt.expectedBinding, binding) + if tt.expectedError != nil || err != nil { + assert.Equal(t, tt.expectedError, err) + return + } + assert.NoError(t, err) + }) + } +} + +func TestExtractBindingFromFunctionBody(t *testing.T) { + tests := []struct { + name string + body *ast.BlockStmt + expectedBinding *metadataschema.Binding + expectedError error + }{ + { + name: "Test with valid binding return statement", + body: createValidFunctionBody(), + expectedBinding: &metadataschema.Binding{ + Input: true, + Output: false, + Operations: []metadataschema.BindingOperation{ + metadataschema.BindingOperation{Name: "create", Description: "Create blob"}, + metadataschema.BindingOperation{Name: "get", Description: "Get blob"}, + }, + }, + expectedError: nil, + }, + { + name: "Test with empty body", + body: &ast.BlockStmt{}, + expectedBinding: nil, + expectedError: errors.New("function body is empty"), + }, + { + name: "Test with no return statement with binding", + body: createBodyWithoutBindingReturn(), + expectedBinding: nil, + expectedError: errors.New("no return statement with a Binding found"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + binding, err := extractBindingFromFunctionBody(tt.body) + assert.Equal(t, tt.expectedBinding, binding) + if tt.expectedError != nil || err != nil { + assert.Equal(t, tt.expectedError, err) + return + } + assert.NoError(t, err) + }) + } +} + +func TestParseBindingStruct(t *testing.T) { + tests := []struct { + name string + expr ast.Expr + expectedBinding *metadataschema.Binding + expectedError error + }{ + { + name: "Test with valid composite literal", + expr: createValidCompositeLit(), + expectedBinding: &metadataschema.Binding{ + Input: true, + Output: false, + Operations: []metadataschema.BindingOperation{ + { + Name: "create", + Description: "Create blob", + }, + { + Name: "get", + Description: "Get blob", + }, + }, + }, + expectedError: nil, + }, + { + name: "Test with invalid composite literal", + expr: createInvalidCompositeLit(), + expectedBinding: nil, + expectedError: errors.New("return value is not a composite literal of type Binding"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + binding, err := parseBindingStruct(tt.expr) + assert.Equal(t, tt.expectedBinding, binding) + if tt.expectedError != nil || err != nil { + assert.Equal(t, tt.expectedError, err) + return + } + assert.NoError(t, err) + }) + } +} + +func TestPopulateBindingField(t *testing.T) { + tests := []struct { + name string + binding *metadataschema.Binding + kv *ast.KeyValueExpr + expectedBinding *metadataschema.Binding + expectedError error + }{ + { + name: "Test populating Input field", + binding: &metadataschema.Binding{}, + kv: createKeyValueExpr("Input", "true"), + expectedBinding: &metadataschema.Binding{ + Input: true, + }, + expectedError: nil, + }, + { + name: "Populate Output field", + binding: &metadataschema.Binding{}, + kv: createKeyValueExpr("Output", "false"), + expectedBinding: &metadataschema.Binding{ + Output: false, + }, + expectedError: nil, + }, + { + name: "Invalid key", + binding: &metadataschema.Binding{}, + kv: createInvalidKeyValueExpr("true"), + expectedBinding: nil, + expectedError: errors.New("key is not an identifier"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := populateBindingField(tt.binding, tt.kv) + if tt.expectedError != nil || err != nil { + assert.Equal(t, tt.expectedError, err) + return + } + assert.NoError(t, err) + }) + } +} + +func TestParseBoolValue(t *testing.T) { + tests := []struct { + name string + expr ast.Expr + expectedResult bool + }{ + { + name: "True expression", + expr: &ast.Ident{Name: "true"}, + expectedResult: true, + }, + { + name: "False expression", + expr: &ast.Ident{Name: "false"}, + expectedResult: false, + }, + { + name: "Non-boolean expression", + expr: &ast.Ident{Name: "notABool"}, + expectedResult: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := parseBoolValue(tt.expr) + assert.Equal(t, tt.expectedResult, result) + }) + } +} + +func TestParseOperationsArray(t *testing.T) { + tests := []struct { + name string + value ast.Expr + expectedOps []metadataschema.BindingOperation + expectedError error + }{ + { + name: "Valid operations array", + value: &ast.CompositeLit{ + Elts: []ast.Expr{ + createBindingOperationCompositeLit("Create", "Create blob"), + createBindingOperationCompositeLit("Get", "Get blob"), + }, + }, + expectedOps: []metadataschema.BindingOperation{ + {Name: "Create", Description: "Create blob"}, + {Name: "Get", Description: "Get blob"}, + }, + expectedError: nil, + }, + { + name: "Invalid element type in operations array", + value: &ast.CompositeLit{ + Elts: []ast.Expr{ + &ast.BasicLit{Kind: token.STRING, Value: `"Invalid"`}, // Invalid element (should be CompositeLit) + }, + }, + expectedOps: nil, + expectedError: errors.New("expected CompositeLit for BindingOperation"), + }, + { + name: "Non-CompositeLit Operations field", + value: &ast.BasicLit{ + Kind: token.STRING, + Value: `"Not a CompositeLit"`, + }, + expectedOps: nil, + expectedError: errors.New("operations field is not a composite literal"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + operations, err := parseOperationsArray(tt.value) + if tt.expectedError != nil { + assert.EqualError(t, err, tt.expectedError.Error()) + } else { + require.NoError(t, err) + assert.Equal(t, tt.expectedOps, operations) + } + }) + } +} + +func TestValidateOperationFields(t *testing.T) { + tests := []struct { + name string + operation metadataschema.BindingOperation + expectedError error + }{ + { + name: "Valid operation with both fields", + operation: metadataschema.BindingOperation{Name: "Create", Description: "Create a notification"}, + expectedError: nil, + }, + { + name: "Missing Name field", + operation: metadataschema.BindingOperation{Description: "Create a notification"}, + expectedError: errors.New("missing 'Name' field in BindingOperation"), + }, + { + name: "Missing Description field", + operation: metadataschema.BindingOperation{Name: "Create"}, + expectedError: errors.New("missing 'Description' field in BindingOperation"), + }, + { + name: "Missing both Name and Description fields", + operation: metadataschema.BindingOperation{}, + expectedError: errors.New("missing 'Name' field in BindingOperation"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := validateOperationFields(tt.operation) + if tt.expectedError != nil { + assert.EqualError(t, err, tt.expectedError.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/.build-tools/cmd/cmd-gen-component-metadata.go b/.build-tools/cmd/cmd-gen-component-metadata.go index 208c4b3076..6671965d3b 100644 --- a/.build-tools/cmd/cmd-gen-component-metadata.go +++ b/.build-tools/cmd/cmd-gen-component-metadata.go @@ -14,660 +14,89 @@ limitations under the License. package cmd import ( - "encoding/json" "fmt" - "go/ast" - "go/parser" - "go/token" "os" - "reflect" - "strings" - "time" - "github.com/dapr/components-contrib/bindings/aws/dynamodb" - "github.com/dapr/components-contrib/bindings/aws/kinesis" - "github.com/dapr/components-contrib/bindings/aws/s3" - "github.com/dapr/components-contrib/bindings/aws/sns" - "github.com/dapr/components-contrib/bindings/azure/cosmosdb" - "github.com/dapr/components-contrib/bindings/azure/cosmosdb/gremlinapi" - "github.com/dapr/components-contrib/bindings/azure/eventgrid" - "github.com/dapr/components-contrib/bindings/azure/openai" - "github.com/dapr/components-contrib/bindings/azure/storagequeues" - "github.com/dapr/components-contrib/build-tools/pkg/componentmetadata" - "github.com/dapr/components-contrib/build-tools/pkg/metadataschema" "github.com/spf13/cobra" - "gopkg.in/yaml.v3" ) +func init() { + const ( + compType = "type" + compBuiltinAuth = "builtinAuth" + compStatus = "status" + compVersion = "version" + compDirection = "direction" + compOrigin = "origin" + compTitle = "title" + ) + generateComponentMetadataNewCmd.Flags().String(compType, "", "The component type (e.g., 'binding')") + generateComponentMetadataNewCmd.Flags().StringSlice(compBuiltinAuth, []string{}, "The authentication profile (e.g., 'aws')") + generateComponentMetadataNewCmd.Flags().String(compStatus, "", "The status of the component (e.g., 'stable')") + generateComponentMetadataNewCmd.Flags().String(compVersion, "", "The version of the component (e.g., 'v1')") + generateComponentMetadataNewCmd.Flags().String(compDirection, "", "The direction of the component (e.g., 'output')") + generateComponentMetadataNewCmd.Flags().String(compOrigin, "", "The origin of the component (e.g., 'Dapr')") + generateComponentMetadataNewCmd.Flags().String(compTitle, "", "The title of the component (e.g., 'My Component')") + + generateComponentMetadataNewCmd.MarkFlagRequired(compType) + // Note: Built in auth profiles are not required + generateComponentMetadataNewCmd.MarkFlagRequired(compStatus) + generateComponentMetadataNewCmd.MarkFlagRequired(compVersion) + // Note: Direction is not required as that is binding specific + generateComponentMetadataNewCmd.MarkFlagRequired(compOrigin) + generateComponentMetadataNewCmd.MarkFlagRequired(compTitle) + + rootCmd.AddCommand(generateComponentMetadataNewCmd) +} + // generateComponentMetadataCmd represents the command to generate the yaml manifest for each component var generateComponentMetadataNewCmd = &cobra.Command{ - Use: "generate-component-metadata-new", + Use: "generate-component-metadata", Short: "Generates the component metadata yaml file per component", Long: `Generates the component metadata yaml file per component so we don't have to rely on community to manually create it.`, Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("sam running new cmd") - // Navigate to the root of the repo + fmt.Println("Running generate-component-metadata command\n") + err := cwdToRepoRoot() if err != nil { - panic(err) + fmt.Printf("Failed to navigate to repo root: %v\n", err) + return } - // Get flag values - componentType, _ := cmd.Flags().GetString("type") - builtinAuth, _ := cmd.Flags().GetStringSlice("builtinAuth") - status, _ := cmd.Flags().GetString("status") - version, _ := cmd.Flags().GetString("version") - direction, _ := cmd.Flags().GetString("direction") - origin, _ := cmd.Flags().GetString("origin") - title, _ := cmd.Flags().GetString("title") + flags := getCmdFlags(cmd) - fmt.Printf("sam origin %v", origin) + // TODO: flag validation for allowed values - // Find all components - list, err := componentmetadata.FindValidComponents(ComponentFolders, ExcludeFolders) - // fmt.Println("sam list %v", list) - if err != nil { - panic(err) - } - // Load the metadata for all components - bundle := metadataschema.Bundle{ - SchemaVersion: "v1", - Date: time.Now().Format("20060102150405"), - Components: make([]*metadataschema.ComponentMetadata, 0, len(list)), - } + fmt.Printf("Origin: %v\n", flags.origin) - _ = bundle - fmt.Printf("sam componentType %s builtinAuth %s status %s version %s direction %s", componentType, builtinAuth, status, version, direction) - filepath := origin //os.Getenv("DOLLAR") - metadataFile := filepath + "/metadata.go" + metadataFile := flags.origin + "/metadata.go" componentPkg := os.Getenv("GOPACKAGE") + checkFileExists(metadataFile) + metadata, _, err := generateMetadataFromStructs(metadataFile, componentPkg+"Metadata", componentPkg) if err != nil { - fmt.Printf("sam error: %v", err) + fmt.Printf("Error generating metadata from structs: %v\n", err) + return } - var componentName string - const ( - awsPrefix = "aws" - azurePrefix = "azure" - ) - switch { - case strings.Contains(origin, awsPrefix): - componentName = awsPrefix + "." + componentPkg - case strings.Contains(origin, azurePrefix): - componentName = azurePrefix + "." + componentPkg - default: - componentName = componentPkg - } - bindingSpecification, err := generateComponentOperations(metadataFile, componentPkg+"Binding") - fmt.Printf("\nsam the binding spec %v\n", bindingSpecification) + componentName := getComponentName(flags.origin, componentPkg) + bindingSpec, err := generateComponentOperations(metadataFile, "Binding") if err != nil { - panic(err) - } - component := metadataschema.ComponentMetadata{ - SchemaVersion: "v2", - Type: componentType, - Name: componentName, - Version: version, - Status: status, - Title: title, - Metadata: metadata, - URLs: supportedComponentURL(componentType, componentPkg), - Binding: bindingSpecification, - } - var awsAuthProfile = metadataschema.BuiltinAuthenticationProfile{Name: "aws"} - var azureAuthProfile = metadataschema.BuiltinAuthenticationProfile{Name: "azuread"} - var gcpAuthProfile = metadataschema.BuiltinAuthenticationProfile{Name: "gcp"} - var allBuiltinProfiles = []metadataschema.BuiltinAuthenticationProfile{awsAuthProfile, azureAuthProfile, gcpAuthProfile} - for _, compProfiles := range builtinAuth { - for _, options := range allBuiltinProfiles { - if strings.ToLower(compProfiles) == strings.ToLower(options.Name) { - component.BuiltInAuthenticationProfiles = append(component.BuiltInAuthenticationProfiles, options) - } - } + fmt.Printf("Component must implement the component.MetadataBuilder interface to auto-generate its manifest: %v\n", err) + return } - // Append built-in metadata properties - err = component.AppendBuiltin() + component, err := assembleComponentMetadata(flags, componentName, metadata, *bindingSpec) if err != nil { - fmt.Printf("sam error from AppendBuildin %v", err) + fmt.Printf("Failed to assemble component metadata: %v\n", err) + return } - - for _, profile := range component.BuiltInAuthenticationProfiles { - appendProfiles, err := metadataschema.ParseBuiltinAuthenticationProfile(profile, component.Title) - if err != nil { - fmt.Printf("sam error from ParseBuiltinAuthenticationProfile %v", err) - } - - component.AuthenticationProfiles = append(component.AuthenticationProfiles, appendProfiles...) - } - - outputFilePath := filepath + "/samhereoutput.yaml" - err = writeToFile(outputFilePath, component) + filePath := flags.origin + "/samhereoutput.yaml" + err = writeToFile(filePath, component) if err != nil { - fmt.Printf("Error writing to file: %v", err) + fmt.Printf("Error writing to file: %v\n", err) } else { - fmt.Printf("Metadata written to %s\n", outputFilePath) - } - - // print everything out if i want - enc := json.NewEncoder(os.Stdout) - enc.SetEscapeHTML(false) - enc.SetIndent("", " ") - err = enc.Encode(component) - if err != nil { - panic(fmt.Errorf("failed to encode bundle to JSON: %w", err)) + fmt.Printf("Metadata written to %s\n", filePath) } }, } - -// generateComponentOperations reads the Go file and extracts the s3Operations variable as a Binding type. -func generateComponentOperations(filePath, varName string) (*metadataschema.Binding, error) { - // Read the Go file - src, err := os.ReadFile(filePath) - if err != nil { - return nil, fmt.Errorf("failed to read file: %w", err) - } - - // Parse the Go source file - fset := token.NewFileSet() - node, err := parser.ParseFile(fset, filePath, src, parser.AllErrors|parser.ParseComments) - if err != nil { - return nil, fmt.Errorf("failed to parse Go file: %w", err) - } - - // Loop through the declarations in the file - for _, decl := range node.Decls { - genDecl, ok := decl.(*ast.GenDecl) - if !ok || genDecl.Tok != token.VAR { - continue - } - - // Check the variable declarations for the name - for _, spec := range genDecl.Specs { - // Extract the variable declaration - vspec, ok := spec.(*ast.ValueSpec) - fmt.Printf("sam here 1 %v %v", vspec, ok) - if !ok || len(vspec.Names) == 0 || vspec.Names[0].Name != varName { - continue - } - - // The variable was found, now process it - fmt.Printf("sam length %v\n", len(vspec.Values)) - if len(vspec.Values) == 1 { - // The variable definition is in the first value position - // Convert the value to a Go expression (it's a literal, so we can use it directly) - structLiteral, ok := vspec.Values[0].(*ast.CompositeLit) - fmt.Printf("sam %v\n\n", ok) - if !ok { - continue - } - - // Initialize an empty Binding struct - binding := &metadataschema.Binding{} - - // Process the struct fields - for _, elt := range structLiteral.Elts { - fmt.Printf("sam now processing fields %v\n", elt) - switch field := elt.(type) { - - case *ast.KeyValueExpr: - // Extract the key (field name) - fmt.Printf("sam field.Key %t\n", field.Key) - key, ok := field.Key.(*ast.Ident) - if !ok { - continue - } - fmt.Printf("sam here is key\n", key) - - // Handle each field based on the key - switch key.Name { - case "Input": - fmt.Printf("\nsam in Input %T\n", field.Value) - // Parse the Input field - if ident, ok := field.Value.(*ast.Ident); ok { - // In case it's an identifier, check its name and manually assign the value - // For example, "true" or "false" might be assigned to Input - switch ident.Name { - case "true": - binding.Input = true - case "false": - binding.Input = false - } - fmt.Printf("sam just set Input value: %v\n", binding.Input) - } - case "Output": - // Parse the Output field - fmt.Printf("sam Output value: %+v\n", field.Value) - // Check if the value is an Ident (identifier) - if ident, ok := field.Value.(*ast.Ident); ok { - // In case it's an identifier, check its name and manually assign the value - // For example, "true" or "false" might be assigned to Output - switch ident.Name { - case "true": - binding.Output = true - case "false": - binding.Output = false - } - fmt.Printf("sam just set Output value: %v\n", binding.Output) - } - case "Operations": - fmt.Printf("sam the oper type %T\n", field.Value) - // Parse the Operations field (which is an array of BindingOperation) - if arrayLit, ok := field.Value.(*ast.CompositeLit); ok { - fmt.Printf("sam in the if for operations %v %v\n", ok, arrayLit) - // Process the array of operations - var operations []metadataschema.BindingOperation - for _, elem := range arrayLit.Elts { - // Process each operation (BindingOperation) - if opLit, ok := elem.(*ast.CompositeLit); ok { - operation := metadataschema.BindingOperation{} - // Process each field in the operation struct - for _, opElt := range opLit.Elts { - if opField, ok := opElt.(*ast.KeyValueExpr); ok { - opKey, ok := opField.Key.(*ast.Ident) - if !ok { - continue - } - - // Map each key in the operation to its corresponding value - switch opKey.Name { - case "Name": - if strVal, ok := opField.Value.(*ast.BasicLit); ok { - operation.Name = strings.Trim(strVal.Value, `"`) - } - case "Description": - if strVal, ok := opField.Value.(*ast.BasicLit); ok { - operation.Description = strings.Trim(strVal.Value, `"`) - } - } - } - } - fmt.Printf("sam just appended op %v\n", operation) - - operations = append(operations, operation) - } - } - binding.Operations = operations - } - } - } - } - - // Return the binding instance - fmt.Printf("\nini func still sam %v %v", binding.Input, binding.Output) - return binding, nil - } - } - } - - return nil, fmt.Errorf("variable %s not found", varName) -} - -func writeToFile(outputFilePath string, component metadataschema.ComponentMetadata) error { - // Open the file for writing (create if not exists) - file, err := os.Create(outputFilePath) - if err != nil { - return fmt.Errorf("could not create file: %v", err) - } - defer file.Close() - - // update the field names to lowercase - for i := range component.Metadata { - component.Metadata[i].Name = lowercaseFirstLetter(component.Metadata[i].Name) - } - - yamlEncoder := yaml.NewEncoder(file) - yamlEncoder.SetIndent(2) - if err := yamlEncoder.Encode(&component); err != nil { - return fmt.Errorf("error encoding YAML: %w", err) - } - - return nil -} - -func init() { - - // Add flags to the command - generateComponentMetadataNewCmd.Flags().String("type", "", "The component type (e.g., 'binding')") - generateComponentMetadataNewCmd.Flags().StringSlice("builtinAuth", []string{}, "The authentication profile (e.g., 'aws')") - generateComponentMetadataNewCmd.Flags().String("status", "", "The status of the component (e.g., 'stable')") - generateComponentMetadataNewCmd.Flags().String("version", "", "The version of the component (e.g., 'v1')") - generateComponentMetadataNewCmd.Flags().String("direction", "", "The direction of the component (e.g., 'output')") - generateComponentMetadataNewCmd.Flags().String("origin", "", "The direction of the component (e.g., 'output')") - generateComponentMetadataNewCmd.Flags().String("title", "", "The direction of the component (e.g., 'output')") - - rootCmd.AddCommand(generateComponentMetadataNewCmd) - -} - -func convertPrefixToPath(componentName string) string { - return strings.ReplaceAll(componentName, ".", "/") -} -func parseJSONTag(tag string) string { - // Remove the backticks and split the tag - tag = strings.Trim(tag, "`") - parts := strings.Split(tag, " ") - for _, part := range parts { - if strings.HasPrefix(part, "json:") { - // Extract the json field name and remove any options like "omitempty" - jsonTag := part[len("json:"):] - jsonTag = strings.Trim(jsonTag, `"`) // Remove surrounding quotes - if commaIdx := strings.Index(jsonTag, ","); commaIdx != -1 { - jsonTag = jsonTag[:commaIdx] - } - return jsonTag - } - } - return "" -} - -type FieldInfo struct { - Name string - JSONTag string - Description string - Required bool - Sensitive bool - Type string - Default string - Example string - AllowedValues []string - Binding *metadataschema.MetadataBinding - Deprecated bool - AuthenticationProfileKey string -} - -// generateMetadataFromStructs processes a Go struct to extract metadata and authentication profile data -func generateMetadataFromStructs(filePath, structName, underlyingComponentName string) ([]metadataschema.Metadata, map[string][]metadataschema.Metadata, error) { - src, err := os.ReadFile(filePath) - if err != nil { - return nil, nil, fmt.Errorf("failed to read file: %w", err) - } - - fmt.Printf("sam the structName %v\n", structName) - - // Parse the Go source file - fset := token.NewFileSet() - node, err := parser.ParseFile(fset, filePath, src, parser.AllErrors|parser.ParseComments) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse Go file: %w", err) - } - - var metadataEntries []metadataschema.Metadata - authProfileMetadataMap := make(map[string][]metadataschema.Metadata) - - // Traverse the AST to locate the struct - for _, decl := range node.Decls { - genDecl, ok := decl.(*ast.GenDecl) - if !ok || genDecl.Tok != token.TYPE { - continue - } - - for _, spec := range genDecl.Specs { - typeSpec, ok := spec.(*ast.TypeSpec) - if !ok || typeSpec.Name.Name != structName { - continue - } - - structType, ok := typeSpec.Type.(*ast.StructType) - if !ok { - continue - } - - // Process each field in the struct - for _, field := range structType.Fields.List { - fieldInfo := extractFieldInfo(field, underlyingComponentName) - if fieldInfo == nil { - continue - } - - metadata := metadataschema.Metadata{ - Name: fieldInfo.JSONTag, - Description: fieldInfo.Description, - Required: fieldInfo.Required, - Sensitive: fieldInfo.Sensitive, - Type: fieldInfo.Type, - Default: fieldInfo.Default, - Example: fieldInfo.Example, - AllowedValues: fieldInfo.AllowedValues, - Binding: fieldInfo.Binding, - Deprecated: fieldInfo.Deprecated, - } - - if fieldInfo.AuthenticationProfileKey != "" { - authProfileMetadataMap[fieldInfo.AuthenticationProfileKey] = append(authProfileMetadataMap[fieldInfo.AuthenticationProfileKey], metadata) - } else { - metadataEntries = append(metadataEntries, metadata) - } - } - } - } - - return metadataEntries, authProfileMetadataMap, nil -} - -func parseAuthProfileTag(tag string) string { - tagParts := strings.Split(tag, " ") - for _, part := range tagParts { - if strings.HasPrefix(part, "authenticationProfile:") { - return strings.Trim(part[len("authenticationProfile:"):], "\"`") - } - } - return "" -} - -// extractFieldInfo extracts metadata for a struct field -func extractFieldInfo(field *ast.Field, componentName string) *FieldInfo { - if len(field.Names) == 0 { - return nil - } - - fieldName := field.Names[0].Name - fieldType := fmt.Sprintf("%s", field.Type) - - // Extract comments - description := "" - if field.Comment != nil { - description = strings.TrimSpace(field.Comment.Text()) - } else if field.Doc != nil { - description = strings.TrimSpace(field.Doc.Text()) - } - - // Extract JSON tag and metadata - var jsonTag string - required := true - authProfileKey := "" - bindingsMeta := metadataschema.MetadataBinding{} - - if field.Tag != nil { - tag := field.Tag.Value - jsonTag = parseJSONTag(tag) - - if strings.Contains(tag, "omitempty") { - required = false - } - if strings.Contains(tag, "mdignore") || strings.Contains(tag, "-") { - return nil - } - if strings.Contains(tag, "authenticationProfile:") { - authProfileKey = parseAuthProfileTag(tag) - } - if strings.Contains(tag, `binding:"input"`) { - bindingsMeta.Input = true - } - if strings.Contains(tag, `binding:"output"`) { - bindingsMeta.Output = true - } - } - - // Populate field info - return &FieldInfo{ - Name: fieldName, - JSONTag: jsonTag, - Description: description, - Required: required, - Sensitive: isFieldSensitive(fieldName), - Type: fieldType, - Default: getDefaultValueForField(componentName, fieldName), - Example: getExampleValueForField(componentName, fieldName), - AllowedValues: []string{}, // TODO: Populate as needed - Binding: &bindingsMeta, - Deprecated: false, - AuthenticationProfileKey: strings.TrimSpace(strings.ToLower(authProfileKey)), - } -} - -func isFieldSensitive(field string) bool { - return strings.Contains(strings.ToLower(field), "key") || strings.Contains(strings.ToLower(field), "token") -} - -func getDefaultValueForField(underlyingComponentName, fieldName string) string { - switch underlyingComponentName { - case "s3": - meta := s3.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "sns": - meta := sns.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "dynamodb": - meta := dynamodb.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "cosmosdb": - meta := cosmosdb.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "gremlinapi": - meta := gremlinapi.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "eventgrid": - meta := eventgrid.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "openai": - meta := openai.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "storagequeues": - meta := storagequeues.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "kinesis": - meta := kinesis.Defaults() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - // Add more cases as needed for other field types - default: - return "Sam TODO need to add the call for defaults/examples" // Fallback default - } -} - -func getExampleValueForField(underlyingComponentName, fieldName string) string { - fmt.Printf("sam fieldName %s", fieldName) - switch underlyingComponentName { - case "s3": - meta := s3.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "sns": - meta := sns.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - // TODO: skipping blobstorage bc it needs a lot of rework to add here - // case "blobstorage": - // meta := blobstorage.Examples() - // defaultsMap := getStructDefaultValue(meta) - // return defaultsMap[fieldName] - case "dynamodb": - meta := dynamodb.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "cosmosdb": - meta := cosmosdb.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "gremlinapi": - meta := gremlinapi.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "eventgrid": - meta := eventgrid.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "openai": - meta := openai.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "storagequeues": - meta := storagequeues.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - case "kinesis": - meta := kinesis.Examples() - defaultsMap := getStructDefaultValue(meta) - return defaultsMap[fieldName] - // Add more cases as needed for other field types - default: - return "Sam TODO need to add the call for defaults/examples" // Fallback default - } -} - -func getStructDefaultValue(meta interface{}) map[string]string { - defaultValues := make(map[string]string) - - // Use reflection to inspect the struct fields - val := reflect.ValueOf(meta) - typ := reflect.TypeOf(meta) - - // Ensure we're working with a pointer to a struct - if val.Kind() == reflect.Ptr { - val = val.Elem() - typ = typ.Elem() - } - - // Iterate over the struct's fields - for i := 0; i < val.NumField(); i++ { - field := val.Field(i) - fieldName := typ.Field(i).Name - - // only process exported fields - // Only process exported fields (fields whose names start with an uppercase letter) - if fieldName[0] >= 'A' && fieldName[0] <= 'Z' { - // Directly use the field's value (which was initialized by New) for the default value - defaultValue := fmt.Sprintf("%v", field.Interface()) - // Store the default value for this field - defaultValues[fieldName] = defaultValue - } - } - - return defaultValues -} - -// lowercaseFirstLetter lowercases the first letter of a string -func lowercaseFirstLetter(s string) string { - if len(s) == 0 { - return s - } - return strings.ToLower(string(s[0])) + s[1:] -} - -func supportedComponentURL(componentType, componentName string) []metadataschema.URL { - referenceURLs := map[string]string{ - "bindings": "bindings", - "state": "state-stores", - "secretstores": "secret-stores", - "TODO": "conversation", - "pubsub": "pubsub", - } - var urls []metadataschema.URL - urls = append(urls, metadataschema.URL{ - Title: "Reference", - URL: fmt.Sprintf("https://docs.dapr.io/reference/components-reference/supported-%s/%s/", - referenceURLs[componentType], componentName), - }) - - return urls -} diff --git a/.build-tools/go.mod b/.build-tools/go.mod index 55dfd11c3b..b94cc0beb7 100644 --- a/.build-tools/go.mod +++ b/.build-tools/go.mod @@ -2,127 +2,33 @@ module github.com/dapr/components-contrib/build-tools go 1.23.0 +replace github.com/dapr/components-contrib/build-tools => /Users/samcoyle/go/src/github.com/forks/dapr/components-contrib/.build-tools + require ( github.com/dapr/components-contrib v0.0.0 github.com/invopop/jsonschema v0.6.0 - github.com/spf13/cobra v1.6.1 + github.com/spf13/cobra v1.8.1 + github.com/stretchr/testify v1.9.0 github.com/xeipuuv/gojsonschema v1.2.1-0.20201027075954-b076d39a02e5 gopkg.in/yaml.v3 v3.0.1 sigs.k8s.io/yaml v1.4.0 ) -require ( - github.com/IBM/sarama v1.43.3 // indirect - github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1-0.20241125194140-078c08b8574a // indirect - github.com/aws/aws-sdk-go v1.50.19 // indirect - github.com/aws/aws-sdk-go-v2 v1.32.4 // indirect - github.com/aws/aws-sdk-go-v2/config v1.28.2 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.43 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 // indirect - github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.3.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 // indirect - github.com/aws/rolesanywhere-credential-helper v1.0.4 // indirect - github.com/aws/smithy-go v1.22.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/eapache/go-resiliency v1.7.0 // indirect - github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect - github.com/eapache/queue v1.1.0 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect - github.com/jackc/pgx/v5 v5.5.5 // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect - github.com/jcmturner/aescts/v2 v2.0.0 // indirect - github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect - github.com/jcmturner/gofork v1.7.6 // indirect - github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect - github.com/jcmturner/rpc/v2 v2.0.3 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/pierrec/lz4/v4 v4.1.21 // indirect - github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spiffe/go-spiffe/v2 v2.1.7 // indirect - github.com/vmware/vmware-go-kcl v1.5.1 // indirect - github.com/zeebo/errs v1.3.0 // indirect - golang.org/x/crypto v0.26.0 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect -) +require github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect require ( - github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai v0.6.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.0.3 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventgrid/armeventgrid/v2 v2.2.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect - github.com/awslabs/kinesis-aggregation/go v0.0.0-20210630091500-54e17340d32f // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.14.0 // indirect - github.com/cloudevents/sdk-go/v2 v2.15.2 // indirect github.com/dapr/kit v0.13.1-0.20240909215017-3823663aa4bb // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect - github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v5 v5.2.1 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/gorilla/websocket v1.5.0 // indirect github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect - github.com/lestrrat-go/blackmagic v1.0.2 // indirect - github.com/lestrrat-go/httpcc v1.0.1 // indirect - github.com/lestrrat-go/httprc v1.0.5 // indirect - github.com/lestrrat-go/iter v1.0.2 // indirect - github.com/lestrrat-go/jwx/v2 v2.0.21 // indirect - github.com/lestrrat-go/option v1.0.1 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.42.0 // indirect - github.com/prometheus/procfs v0.11.0 // indirect - github.com/rs/zerolog v1.31.0 // indirect - github.com/segmentio/asm v1.2.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/supplyon/gremcos v0.1.40 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.49.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - go.uber.org/atomic v1.10.0 // indirect - google.golang.org/protobuf v1.34.1 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/apimachinery v0.26.10 // indirect ) diff --git a/.build-tools/go.sum b/.build-tools/go.sum index cfc96b9035..931844f1cb 100644 --- a/.build-tools/go.sum +++ b/.build-tools/go.sum @@ -1,268 +1,52 @@ -github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= -github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai v0.6.0 h1:FQOmDxJj1If0D0khZR00MDa2Eb+k9BBsSaK7cEbLwkk= -github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai v0.6.0/go.mod h1:X0+PSrHOZdTjkiEhgv53HS5gplbzVVl2jd6hQRYSS3c= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= -github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.0.3 h1:gBWC0dYF3aO+7xGxL0Ccjv9BmnV30C8VZIrUPlMct6g= -github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos v1.0.3/go.mod h1:7LBWaO4KRASAo9VpfhpxQKkdY6PBwkv9UDKzL9Sajuw= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventgrid/armeventgrid/v2 v2.2.0 h1:rK2PztrELX4EIQV1OWaM5zXPl9OAjv/+/jg2kmHKmG0= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/eventgrid/armeventgrid/v2 v2.2.0/go.mod h1:GdZIPeg5TQxW50uJ8y9Eqz2FT9taolHoGawJg/KI2o4= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0/go.mod h1:LRr2FzBTQlONPPa5HREE5+RjSCTXl7BwOvYOaWTqCaI= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1 h1:7CBQ+Ei8SP2c6ydQTGCCrS35bDxgTMfoP2miAwK++OU= -github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.1.1/go.mod h1:c/wcGeGx5FUPbM/JltUYHZcKmigwyVLJlDq+4HdtXaw= -github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.0 h1:lJwNFV+xYjHREUTHJKx/ZF6CJSt9znxmLw9DqSTvyRU= -github.com/Azure/azure-sdk-for-go/sdk/storage/azqueue v1.0.0/go.mod h1:GfT0aGew8Qj5yiQVqOO5v7N8fanbJGyUoHqXg56qcVY= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= -github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= -github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/IBM/sarama v1.43.3 h1:Yj6L2IaNvb2mRBop39N7mmJAHBVY3dTPncr3qGVkxPA= -github.com/IBM/sarama v1.43.3/go.mod h1:FVIRaLrhK3Cla/9FfRF5X9Zua2KpS3SYIXxhac1H+FQ= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1-0.20241125194140-078c08b8574a h1:QFemvMGPnajaeRBkFc1HoEA7qzVjUv+rkYb1/ps1/UE= -github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1-0.20241125194140-078c08b8574a/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI= -github.com/aws/aws-sdk-go v1.19.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.50.19 h1:YSIDKRSkh/TW0RPWoocdLqtC/T5W6IGBVhFs6P7Qcac= -github.com/aws/aws-sdk-go v1.50.19/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE= -github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= -github.com/aws/aws-sdk-go-v2/config v1.28.2 h1:FLvWA97elBiSPdIol4CXfIAY1wlq3KzoSgkMuZSuSe8= -github.com/aws/aws-sdk-go-v2/config v1.28.2/go.mod h1:hNmQsKfUqpKz2yfnZUB60GCemPmeqAalVTui0gOxjAE= -github.com/aws/aws-sdk-go-v2/credentials v1.17.43 h1:SEGdVOOE1Wyr2XFKQopQ5GYjym3nYHcphesdt78rNkY= -github.com/aws/aws-sdk-go-v2/credentials v1.17.43/go.mod h1:3aiza5kSyAE4eujSanOkSkAmX/RnVqslM+GRQ/Xvv4c= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= -github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.3.10 h1:z6fAXB4HSuYjrE/P8RU3NdCaN+EPaeq/+80aisCjuF8= -github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.3.10/go.mod h1:PoPjOi7j+/DtKIGC58HRfcdWKBPYYXwdKnRG+po+hzo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.4 h1:BqE3NRG6bsODh++VMKMsDmFuJTHrdD4rJZqHjDeF6XI= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.4/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= -github.com/aws/rolesanywhere-credential-helper v1.0.4 h1:kHIVVdyQQiFZoKBP+zywBdFilGCS8It+UvW5LolKbW8= -github.com/aws/rolesanywhere-credential-helper v1.0.4/go.mod h1:QVGNxlDlYhjR0/ZUee7uGl0hNChWidNpe2+GD87Buqk= -github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= -github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= -github.com/awslabs/kinesis-aggregation/go v0.0.0-20210630091500-54e17340d32f h1:Pf0BjJDga7C98f0vhw+Ip5EaiE07S3lTKpIYPNS0nMo= -github.com/awslabs/kinesis-aggregation/go v0.0.0-20210630091500-54e17340d32f/go.mod h1:SghidfnxvX7ribW6nHI7T+IBbc9puZ9kk5Tx/88h8P4= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.14.0 h1:dEopBSOSjB5fM9r76ufM44AVj9Dnz2IOM0Xs6FVxZRM= -github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.14.0/go.mod h1:qDSbb0fgIfFNjZrNTPtS5MOMScAGyQtn1KlSvoOdqYw= -github.com/cloudevents/sdk-go/v2 v2.15.2 h1:54+I5xQEnI73RBhWHxbI1XJcqOFOVJN85vb41+8mHUc= -github.com/cloudevents/sdk-go/v2 v2.15.2/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/dapr/kit v0.13.1-0.20240909215017-3823663aa4bb h1:ahLO7pMmX6HAuT6/RxYWBY4AN2fXQJcYlU1msY6Kt7U= github.com/dapr/kit v0.13.1-0.20240909215017-3823663aa4bb/go.mod h1:Hz1W2LmWfA4UX/12MdA+brsf+np6f/1dJt6C6F63cjI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= -github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= -github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4ALJ04o5Qqpdz8XLIpNA3WM/iSIXqxtqo7UGVws= -github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= -github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= -github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= -github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= -github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk= github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/invopop/jsonschema v0.6.0 h1:8e+xY8ZEn8gDHUYylSlLHy22P+SLeIRIHv3nM3hCbmY= github.com/invopop/jsonschema v0.6.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= -github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= -github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= -github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= -github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= -github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= -github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= -github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= -github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= -github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= -github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= -github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= -github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= -github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= -github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= -github.com/lestrrat-go/httprc v1.0.5 h1:bsTfiH8xaKOJPrg1R+E3iE/AWZr/x0Phj9PBTG/OLUk= -github.com/lestrrat-go/httprc v1.0.5/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= -github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= -github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx/v2 v2.0.21 h1:jAPKupy4uHgrHFEdjVjNkUgoBKtVDgrQPB/h55FHrR0= -github.com/lestrrat-go/jwx/v2 v2.0.21/go.mod h1:09mLW8zto6bWL9GbwnqAli+ArLf+5M33QLQPDggkUWM= -github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= -github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4 h1:BpfhmLKZf+SjVanKKhCgf3bg+511DmU9eDQTen7LLbY= github.com/mitchellh/mapstructure v1.5.1-0.20220423185008-bf980b35cac4/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= -github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= -github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= -github.com/prometheus/procfs v0.11.0 h1:5EAgkfkMl659uZPbe9AS2N68a7Cc1TJbPEuGzFuRbyk= -github.com/prometheus/procfs v0.11.0/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A= -github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= -github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spiffe/go-spiffe/v2 v2.1.7 h1:VUkM1yIyg/x8X7u1uXqSRVRCdMdfRIEdFBzpqoeASGk= -github.com/spiffe/go-spiffe/v2 v2.1.7/go.mod h1:QJDGdhXllxjxvd5B+2XnhhXB/+rC8gr+lNrtOryiWeE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/supplyon/gremcos v0.1.40 h1:OFJw3MV44HNE9N6SKYK0zRBbEwyugyyjjqeXiGi5E3w= -github.com/supplyon/gremcos v0.1.40/go.mod h1:LI6lxKObicSoIw1N04rHyjz9tGSaevM6Ydbo3XfyZfA= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE= -github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= -github.com/vmware/vmware-go-kcl v1.5.1 h1:1rJLfAX4sDnCyatNoD/WJzVafkwST6u/cgY/Uf2VgHk= -github.com/vmware/vmware-go-kcl v1.5.1/go.mod h1:kXJmQ6h0dRMRrp1uWU9XbIXvwelDpTxSPquvQUBdpbo= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -272,106 +56,41 @@ github.com/xeipuuv/gojsonschema v1.2.1-0.20201027075954-b076d39a02e5 h1:ImnGIsrc github.com/xeipuuv/gojsonschema v1.2.1-0.20201027075954-b076d39a02e5/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= -github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= -go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434 h1:umK/Ey0QEzurTNlsV3R+MfxHAb78HCEX/IkuR+zH4WQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240509183442-62759503f434/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= -google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20 h1:MLBCGN1O7GzIx+cBiwfYPwtmZ41U3Mn/cotLJciaArI= -google.golang.org/grpc/examples v0.0.0-20230224211313-3775f633ce20/go.mod h1:Nr5H8+MlGWr5+xX/STzdoEqJrO+YteqFbMyCsrb6mH0= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= k8s.io/apimachinery v0.26.10 h1:aE+J2KIbjctFqPp3Y0q4Wh2PD+l1p2g3Zp4UYjSvtGU= k8s.io/apimachinery v0.26.10/go.mod h1:iT1ZP4JBP34wwM+ZQ8ByPEQ81u043iqAcsJYftX9amM= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/Makefile b/Makefile index 6a4d64f0d8..12ab04d918 100644 --- a/Makefile +++ b/Makefile @@ -220,7 +220,7 @@ check-component-metadata-schema-diff: component-metadata-schema ################################################################################ .PHONY: component-metadata-manifest component-metadata-manifest: - $(RUN_BUILD_TOOLS) generate-component-metadata-new --type=$(type) --builtinAuth=$(builtinAuth) --status=$(status) --version=$(version) --direction=$(direction) --origin=$(origin) --title='$(title)' + $(RUN_BUILD_TOOLS) generate-component-metadata --type=$(type) --builtinAuth=$(builtinAuth) --status=$(status) --version=$(version) --direction=$(direction) --origin=$(origin) --title='$(title)' ################################################################################ # Component metadata bundle targets # diff --git a/bindings/apns/apns.go b/bindings/apns/apns.go index ca633185d3..a770fed394 100644 --- a/bindings/apns/apns.go +++ b/bindings/apns/apns.go @@ -82,7 +82,7 @@ func NewAPNS(logger logger.Logger) bindings.OutputBinding { // Init will configure the APNS output binding using the metadata specified // in the binding's configuration. func (a *APNS) Init(ctx context.Context, metadata bindings.Metadata) error { - m := APNSmetadata{} + m := apnsMetadata{} err := kitmd.DecodeMetadata(metadata.Properties, &m) if err != nil { return err @@ -172,7 +172,7 @@ func (a *APNS) sendPushNotificationToAPNS(ctx context.Context, deviceToken strin return a.client.Do(httpRequest) } -func (a *APNS) makeURLPrefix(metadata APNSmetadata) error { +func (a *APNS) makeURLPrefix(metadata apnsMetadata) error { if metadata.Development { a.logger.Debug("Using the development APNS service") a.urlPrefix = developmentPrefix @@ -184,7 +184,7 @@ func (a *APNS) makeURLPrefix(metadata APNSmetadata) error { return nil } -func (a *APNS) extractKeyID(metadata APNSmetadata) error { +func (a *APNS) extractKeyID(metadata apnsMetadata) error { if metadata.KeyID != "" { a.authorizationBuilder.keyID = metadata.KeyID @@ -194,7 +194,7 @@ func (a *APNS) extractKeyID(metadata APNSmetadata) error { return errors.New("the key-id parameter is required") } -func (a *APNS) extractTeamID(metadata APNSmetadata) error { +func (a *APNS) extractTeamID(metadata apnsMetadata) error { if metadata.TeamID != "" { a.authorizationBuilder.teamID = metadata.TeamID @@ -204,7 +204,7 @@ func (a *APNS) extractTeamID(metadata APNSmetadata) error { return errors.New("the team-id parameter is required") } -func (a *APNS) extractPrivateKey(metadata APNSmetadata) error { +func (a *APNS) extractPrivateKey(metadata apnsMetadata) error { if metadata.PrivateKey != "" { block, _ := pem.Decode([]byte(metadata.PrivateKey)) if block == nil { @@ -256,7 +256,7 @@ func makeErrorResponse(httpResponse *http.Response) (*bindings.InvokeResponse, e // GetComponentMetadata returns the metadata of the component. func (a *APNS) GetComponentMetadata() (metadataInfo contribMetadata.MetadataMap) { - metadataStruct := APNSmetadata{} + metadataStruct := apnsMetadata{} contribMetadata.GetMetadataInfoFromStructType(reflect.TypeOf(metadataStruct), &metadataInfo, contribMetadata.BindingType) return } diff --git a/bindings/apns/metadata.go b/bindings/apns/metadata.go index 4677908d56..68ff139b3a 100644 --- a/bindings/apns/metadata.go +++ b/bindings/apns/metadata.go @@ -1,3 +1,5 @@ +//go:generate make -f ../../Makefile component-metadata-manifest type=bindings status=stable version=v1 direction=output origin=$PWD "title=Apple Push Notification Service" + /* Copyright 2024 The Dapr Authors Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,10 +15,56 @@ limitations under the License. package apns -type APNSmetadata struct { - Development bool `mapstructure:"development"` - KeyID string `mapstructure:"key-id"` - TeamID string `mapstructure:"team-id"` - PrivateKey string `mapstructure:"private-key"` +import ( + "github.com/dapr/components-contrib/build-tools/pkg/metadataschema" + "github.com/dapr/components-contrib/common/component" +) + +// implement MetadataBuilder so each component will be properly parsed for the ast to auto-generate metadata manifest. +var _ component.MetadataBuilder = &apnsMetadata{} + +type apnsMetadata struct { + // Tells the binding which APNs service to use. Set to "true" to use the development service or "false" to use the production service. + Development bool `json:"development,omitempty" mapstructure:"development"` + // The identifier for the private key from the Apple Developer Portal. + KeyID string `json:"key-id" mapstructure:"key-id"` + // The identifier for the organization or author from the Apple Developer Portal. + TeamID string `json:"team-id" mapstructure:"team-id"` + // A PKCS #8-formatted private key. It is intended that the private key is stored in the secret store and not exposed directly in the configuration. + PrivateKey string `json:"privateKey" mapstructure:"private-key"` + + // TODO: docs need Development required set to false } +// Set the default values here. +// This unifies the setup across all components, +// and makes it easy for us to auto-generate the component metadata default values, +// while also leveraging the default values for types thanks to Go. +func (a *apnsMetadata) Defaults() any { + return apnsMetadata{ + Development: true, + } +} + +// Note: we do not include any mdignored field. +func (a *apnsMetadata) Examples() any { + return apnsMetadata{ + Development: false, + KeyID: "private-key-id", + TeamID: "team-id", + PrivateKey: "pem file", + } +} + +func (a *apnsMetadata) Binding() metadataschema.Binding { + return metadataschema.Binding{ + Input: false, + Output: true, + Operations: []metadataschema.BindingOperation{ + { + Name: "create", + Description: "Create notification", + }, + }, + } +} diff --git a/bindings/aws/dynamodb/metadata.go b/bindings/aws/dynamodb/metadata.go index 267c3271cc..2fde56c0ab 100644 --- a/bindings/aws/dynamodb/metadata.go +++ b/bindings/aws/dynamodb/metadata.go @@ -1,3 +1,5 @@ +//go:generate make -f ../../../Makefile component-metadata-manifest type=bindings builtinAuth="aws" status=stable version=v1 direction=output origin=$PWD "title=AWS DynamoDB" + /* Copyright 2024 The Dapr Authors Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,6 +15,14 @@ limitations under the License. package dynamodb +import ( + "github.com/dapr/components-contrib/build-tools/pkg/metadataschema" + "github.com/dapr/components-contrib/common/component" +) + +// implement MetadataBuilder so each component will be properly parsed for the ast to auto-generate metadata manifest. +var _ component.MetadataBuilder = &dynamodbMetadata{} + type dynamodbMetadata struct { Region string `json:"region" mapstructure:"region" mdignore:"true"` Endpoint string `json:"endpoint" mapstructure:"endpoint" mdignore:"true"` @@ -26,14 +36,27 @@ type dynamodbMetadata struct { // This unifies the setup across all components, // and makes it easy for us to auto-generate the component metadata default values, // while also leveraging the default values for types thanks to Go. -func Defaults() dynamodbMetadata { +func (d *dynamodbMetadata) Defaults() any { return dynamodbMetadata{} } // Note: we do not include any mdignored field. -func Examples() dynamodbMetadata { +func (d *dynamodbMetadata) Examples() any { return dynamodbMetadata{ Endpoint: "http://localhost:4566", Table: "Contracts", } } + +func (d *dynamodbMetadata) Binding() metadataschema.Binding { + return metadataschema.Binding{ + Input: false, + Output: true, + Operations: []metadataschema.BindingOperation{ + { + Name: "create", + Description: "Create a table", + }, + }, + } +} diff --git a/bindings/aws/s3/metadata.go b/bindings/aws/s3/metadata.go index b0747910ae..36774681ed 100644 --- a/bindings/aws/s3/metadata.go +++ b/bindings/aws/s3/metadata.go @@ -15,9 +15,13 @@ limitations under the License. package s3 -import "github.com/dapr/components-contrib/build-tools/pkg/metadataschema" +import ( + "github.com/dapr/components-contrib/build-tools/pkg/metadataschema" + "github.com/dapr/components-contrib/common/component" +) -//go:generate make -f ../../../Makefile component-metadata-manifest type=bindings builtinAuth="aws" status=stable version=v1 direction=output origin=$PWD "title=AWS S3" +// implement MetadataBuilder so each component will be properly parsed for the ast to auto-generate metadata manifest. +var _ component.MetadataBuilder = &s3Metadata{} type s3Metadata struct { // AccessKey is the AWS access key to authenticate requests. @@ -55,12 +59,12 @@ type s3Metadata struct { // This unifies the setup across all components, // and makes it easy for us to auto-generate the component metadata default values, // while also leveraging the default values for types thanks to Go. -func Defaults() s3Metadata { +func (s3 *s3Metadata) Defaults() any { return s3Metadata{} } // Note: we do not include any mdignored field. -func Examples() s3Metadata { +func (s3 *s3Metadata) Examples() any { return s3Metadata{ Endpoint: "http://localhost:4566", Bucket: "bucket", @@ -72,25 +76,27 @@ func Examples() s3Metadata { } } -var s3Binding = metadataschema.Binding{ - Input: false, - Output: true, - Operations: []metadataschema.BindingOperation{ - { - Name: "create", - Description: "Create blob", - }, - { - Name: "get", - Description: "Get blob", - }, - { - Name: "delete", - Description: "Delete blob", +func (s3 *s3Metadata) Binding() metadataschema.Binding { + return metadataschema.Binding{ + Input: false, + Output: true, + Operations: []metadataschema.BindingOperation{ + { + Name: "create", + Description: "Create blob", + }, + { + Name: "get", + Description: "Get blob", + }, + { + Name: "delete", + Description: "Delete blob", + }, + { + Name: "list", + Description: "List blob", + }, }, - { - Name: "list", - Description: "List blob", - }, - }, + } } diff --git a/bindings/azure/blobstorage/blobstorage.go b/bindings/azure/blobstorage/blobstorage.go index b132f9bf4a..9286324dc7 100644 --- a/bindings/azure/blobstorage/blobstorage.go +++ b/bindings/azure/blobstorage/blobstorage.go @@ -1,3 +1,5 @@ +//go:generate echo TODO bindings/azure/blobstorage + /* Copyright 2021 The Dapr Authors Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/common/component/interface.go b/common/component/interface.go new file mode 100644 index 0000000000..e944397d3e --- /dev/null +++ b/common/component/interface.go @@ -0,0 +1,9 @@ +package component + +import "github.com/dapr/components-contrib/build-tools/pkg/metadataschema" + +type MetadataBuilder interface { + Defaults() any + Examples() any + Binding() metadataschema.Binding +}