diff --git a/cmd/protoc-gen-go-errors/errors.go b/cmd/protoc-gen-go-errors/errors.go index f09c89ea8..883e236ca 100644 --- a/cmd/protoc-gen-go-errors/errors.go +++ b/cmd/protoc-gen-go-errors/errors.go @@ -89,6 +89,12 @@ func genErrorsReason(_ *protogen.Plugin, _ *protogen.File, g *protogen.Generated comment = v.Comments.Trailing.String() } + var enumDetails *errorDetails + eDetails := proto.GetExtension(v.Desc.Options(), errors.E_Details) + if d := eDetails.(*errors.Details); d != nil { + enumDetails = getDetails(d) + } + err := &errorInfo{ Name: string(enum.Desc.Name()), Value: string(v.Desc.Name()), @@ -96,6 +102,8 @@ func genErrorsReason(_ *protogen.Plugin, _ *protogen.File, g *protogen.Generated HTTPCode: enumCode, Comment: comment, HasComment: len(comment) > 0, + Details: enumDetails, + HasDetails: enumDetails != nil, } ew.Errors = append(ew.Errors, err) } @@ -107,6 +115,14 @@ func genErrorsReason(_ *protogen.Plugin, _ *protogen.File, g *protogen.Generated return false } +func getDetails(d *errors.Details) *errorDetails { + details := &errorDetails{ + Format: d.GetFormat(), + HasFormat: d.Format != nil, + } + return details +} + func case2Camel(name string) string { if !strings.Contains(name, "_") { if name == strings.ToUpper(name) { diff --git a/cmd/protoc-gen-go-errors/errors/errors.pb.go b/cmd/protoc-gen-go-errors/errors/errors.pb.go index 16eb19d6c..b95599c61 100644 --- a/cmd/protoc-gen-go-errors/errors/errors.pb.go +++ b/cmd/protoc-gen-go-errors/errors/errors.pb.go @@ -92,6 +92,53 @@ func (x *Error) GetMetadata() map[string]string { return nil } +type Details struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Format *string `protobuf:"bytes,1,opt,name=format,proto3,oneof" json:"format,omitempty"` +} + +func (x *Details) Reset() { + *x = Details{} + if protoimpl.UnsafeEnabled { + mi := &file_errors_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Details) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Details) ProtoMessage() {} + +func (x *Details) ProtoReflect() protoreflect.Message { + mi := &file_errors_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Details.ProtoReflect.Descriptor instead. +func (*Details) Descriptor() ([]byte, []int) { + return file_errors_proto_rawDescGZIP(), []int{1} +} + +func (x *Details) GetFormat() string { + if x != nil && x.Format != nil { + return *x.Format + } + return "" +} + var file_errors_proto_extTypes = []protoimpl.ExtensionInfo{ { ExtendedType: (*descriptorpb.EnumOptions)(nil), @@ -109,6 +156,14 @@ var file_errors_proto_extTypes = []protoimpl.ExtensionInfo{ Tag: "varint,1109,opt,name=code", Filename: "errors.proto", }, + { + ExtendedType: (*descriptorpb.EnumValueOptions)(nil), + ExtensionType: (*Details)(nil), + Field: 1110, + Name: "errors.details", + Tag: "bytes,1110,opt,name=details", + Filename: "errors.proto", + }, } // Extension fields to descriptorpb.EnumOptions. @@ -121,6 +176,8 @@ var ( var ( // optional int32 code = 1109; E_Code = &file_errors_proto_extTypes[1] + // optional errors.Details details = 1110; + E_Details = &file_errors_proto_extTypes[2] ) var File_errors_proto protoreflect.FileDescriptor @@ -141,21 +198,29 @@ var file_errors_proto_rawDesc = []byte{ 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x40, - 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x1c, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd4, 0x08, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x64, 0x65, - 0x3a, 0x36, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd5, 0x08, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x42, 0x59, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2e, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x73, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, - 0x74, 0x6f, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x3b, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x73, 0xa2, 0x02, 0x0c, 0x4b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x45, 0x72, 0x72, - 0x6f, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x31, + 0x0a, 0x07, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x1b, 0x0a, 0x06, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x3a, 0x40, 0x0a, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0xd4, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, + 0x6f, 0x64, 0x65, 0x3a, 0x36, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, + 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd5, + 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x50, 0x0a, 0x07, 0x64, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd6, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0f, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x73, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x88, 0x01, 0x01, 0x42, 0x59, 0x0a, + 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x6b, 0x72, 0x61, 0x74, + 0x6f, 0x73, 0x2e, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x50, 0x01, 0x5a, 0x2c, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, + 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x76, 0x32, 0x2f, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x73, 0x3b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0xa2, 0x02, 0x0c, 0x4b, 0x72, 0x61, 0x74, + 0x6f, 0x73, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -170,21 +235,24 @@ func file_errors_proto_rawDescGZIP() []byte { return file_errors_proto_rawDescData } -var file_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_errors_proto_goTypes = []interface{}{ (*Error)(nil), // 0: errors.Error - nil, // 1: errors.Error.MetadataEntry - (*descriptorpb.EnumOptions)(nil), // 2: google.protobuf.EnumOptions - (*descriptorpb.EnumValueOptions)(nil), // 3: google.protobuf.EnumValueOptions + (*Details)(nil), // 1: errors.Details + nil, // 2: errors.Error.MetadataEntry + (*descriptorpb.EnumOptions)(nil), // 3: google.protobuf.EnumOptions + (*descriptorpb.EnumValueOptions)(nil), // 4: google.protobuf.EnumValueOptions } var file_errors_proto_depIdxs = []int32{ - 1, // 0: errors.Error.metadata:type_name -> errors.Error.MetadataEntry - 2, // 1: errors.default_code:extendee -> google.protobuf.EnumOptions - 3, // 2: errors.code:extendee -> google.protobuf.EnumValueOptions - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 1, // [1:3] is the sub-list for extension extendee + 2, // 0: errors.Error.metadata:type_name -> errors.Error.MetadataEntry + 3, // 1: errors.default_code:extendee -> google.protobuf.EnumOptions + 4, // 2: errors.code:extendee -> google.protobuf.EnumValueOptions + 4, // 3: errors.details:extendee -> google.protobuf.EnumValueOptions + 1, // 4: errors.details:type_name -> errors.Details + 5, // [5:5] is the sub-list for method output_type + 5, // [5:5] is the sub-list for method input_type + 4, // [4:5] is the sub-list for extension type_name + 1, // [1:4] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name } @@ -206,15 +274,28 @@ func file_errors_proto_init() { return nil } } + file_errors_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Details); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } + file_errors_proto_msgTypes[1].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_errors_proto_rawDesc, NumEnums: 0, - NumMessages: 2, - NumExtensions: 2, + NumMessages: 3, + NumExtensions: 3, NumServices: 0, }, GoTypes: file_errors_proto_goTypes, diff --git a/cmd/protoc-gen-go-errors/errors/errors.proto b/cmd/protoc-gen-go-errors/errors/errors.proto index ff6766b49..9efa5548b 100644 --- a/cmd/protoc-gen-go-errors/errors/errors.proto +++ b/cmd/protoc-gen-go-errors/errors/errors.proto @@ -22,4 +22,9 @@ extend google.protobuf.EnumOptions { extend google.protobuf.EnumValueOptions { int32 code = 1109; + optional Details details = 1110; +} + +message Details { + optional string format = 1; } diff --git a/cmd/protoc-gen-go-errors/errorsTemplate.tpl b/cmd/protoc-gen-go-errors/errorsTemplate.tpl index b77a93905..cb3e2c44e 100644 --- a/cmd/protoc-gen-go-errors/errorsTemplate.tpl +++ b/cmd/protoc-gen-go-errors/errorsTemplate.tpl @@ -14,4 +14,17 @@ func Error{{ .CamelValue }}(format string, args ...interface{}) *errors.Error { return errors.New({{ .HTTPCode }}, {{ .Name }}_{{ .Value }}.String(), fmt.Sprintf(format, args...)) } +{{ if .HasDetails }} + +{{ if .Details.HasFormat }} + +{{ if .HasComment }}{{ .Comment }}{{ end -}} +func Error{{ .CamelValue }}WithFormat(args ...interface{}) *errors.Error { + return errors.New({{ .HTTPCode }}, {{ .Name }}_{{ .Value }}.String(), fmt.Sprintf("{{ .Details.Format }}", args...)) +} + +{{- end }} + {{- end }} + +{{- end }} \ No newline at end of file diff --git a/cmd/protoc-gen-go-errors/template.go b/cmd/protoc-gen-go-errors/template.go index 24850822f..a2e6340a0 100644 --- a/cmd/protoc-gen-go-errors/template.go +++ b/cmd/protoc-gen-go-errors/template.go @@ -16,6 +16,13 @@ type errorInfo struct { CamelValue string Comment string HasComment bool + Details *errorDetails + HasDetails bool +} + +type errorDetails struct { + Format string + HasFormat bool } type errorWrapper struct { diff --git a/third_party/errors/errors.proto b/third_party/errors/errors.proto index 331f0fbaa..49bc4bc9f 100644 --- a/third_party/errors/errors.proto +++ b/third_party/errors/errors.proto @@ -15,4 +15,9 @@ extend google.protobuf.EnumOptions { extend google.protobuf.EnumValueOptions { int32 code = 1109; + optional Details details = 1110; +} + +message Details { + optional string format = 1; }