@@ -23,23 +23,19 @@ type protoFile struct {
2323}
2424
2525type ProtoSchemaSet struct {
26- Owner string `toml:"owner"`
27- Repository string `toml:"repository"`
28- Ref string `toml:"ref"` // ref or tag or commit SHA
29- Folders []string `toml:"folders"` // if not provided, all protos will be fetched, otherwise only protos in these folders will be fetched
26+ Owner string `toml:"owner"`
27+ Repository string `toml:"repository"`
28+ Ref string `toml:"ref"` // ref or tag or commit SHA
29+ Folders []string `toml:"folders"` // if not provided, all protos will be fetched, otherwise only protos in these folders will be fetched
30+ SubjectPrefix string `toml:"subject_prefix"` // optional prefix for subjects
3031}
3132
3233// SubjectNamingStrategyFn is a function that is used to determine the subject name for a given proto file in a given repo
33- type SubjectNamingStrategyFn func (path , source string , repoConfig ProtoSchemaSet ) (string , error )
34+ type SubjectNamingStrategyFn func (subjectPrefix string , protoFile protoFile , repoConfig ProtoSchemaSet ) (string , error )
3435
3536// RepositoryToSubjectNamingStrategyFn is a map of repository names to SubjectNamingStrategyFn functions
3637type RepositoryToSubjectNamingStrategyFn map [string ]SubjectNamingStrategyFn
3738
38- // DefaultRepositoryToSubjectNamingStrategy is a map of repository names to SubjectNamingStrategyFn functions
39- var DefaultRepositoryToSubjectNamingStrategy = RepositoryToSubjectNamingStrategyFn {
40- "smartcontractkit/chainlink-protos" : ChainlinkProtosSubjectNamingStrategy ,
41- }
42-
4339func ValidateRepoConfiguration (repoConfig ProtoSchemaSet ) error {
4440 if repoConfig .Owner == "" {
4541 return errors .New ("owner is required" )
@@ -56,7 +52,7 @@ func ValidateRepoConfiguration(repoConfig ProtoSchemaSet) error {
5652}
5753
5854func DefaultRegisterAndFetchProtos (ctx context.Context , client * github.Client , protoSchemaSets []ProtoSchemaSet , schemaRegistryURL string ) error {
59- return RegisterAndFetchProtos (ctx , client , protoSchemaSets , schemaRegistryURL , DefaultRepositoryToSubjectNamingStrategy )
55+ return RegisterAndFetchProtos (ctx , client , protoSchemaSets , schemaRegistryURL , map [ string ] SubjectNamingStrategyFn {} )
6056}
6157
6258func RegisterAndFetchProtos (ctx context.Context , client * github.Client , protoSchemaSets []ProtoSchemaSet , schemaRegistryURL string , repoToSubjectNamingStrategy RepositoryToSubjectNamingStrategyFn ) error {
@@ -69,10 +65,10 @@ func RegisterAndFetchProtos(ctx context.Context, client *github.Client, protoSch
6965 }
7066
7167 protoMap := make (map [string ]string )
72- subjectMap := make (map [string ]string )
68+ subjects := make (map [string ]string )
7369
74- for _ , pf := range protos {
75- protoMap [pf .Path ] = pf .Content
70+ for _ , proto := range protos {
71+ protoMap [proto .Path ] = proto .Content
7672
7773 var subjectStrategy SubjectNamingStrategyFn
7874 if strategy , ok := repoToSubjectNamingStrategy [protoSchemaSet .Owner + "/" + protoSchemaSet .Repository ]; ok {
@@ -81,14 +77,14 @@ func RegisterAndFetchProtos(ctx context.Context, client *github.Client, protoSch
8177 subjectStrategy = DefaultSubjectNamingStrategy
8278 }
8379
84- subject , nameErr := subjectStrategy (pf . Path , pf . Content , protoSchemaSet )
80+ subjectMessage , nameErr := subjectStrategy (protoSchemaSet . SubjectPrefix , proto , protoSchemaSet )
8581 if nameErr != nil {
86- return errors .Wrapf (nameErr , "failed to extract message name from %s" , pf .Path )
82+ return errors .Wrapf (nameErr , "failed to extract message name from %s" , proto .Path )
8783 }
88- subjectMap [ pf .Path ] = subject
84+ subjects [ proto .Path ] = subjectMessage
8985 }
9086
91- registerErr := registerAllWithTopologicalSortingByTrial (schemaRegistryURL , protoMap , subjectMap )
87+ registerErr := registerAllWithTopologicalSortingByTrial (schemaRegistryURL , protoMap , subjects )
9288 if registerErr != nil {
9389 return errors .Wrapf (registerErr , "failed to register protos from %s/%s" , protoSchemaSet .Owner , protoSchemaSet .Repository )
9490 }
@@ -97,46 +93,39 @@ func RegisterAndFetchProtos(ctx context.Context, client *github.Client, protoSch
9793 return nil
9894}
9995
100- func DefaultSubjectNamingStrategy (path , source string , protoSchemaSet ProtoSchemaSet ) (string , error ) {
101- messageName , nameErr := extractTopLevelMessageNamesWithRegex ( source )
102- if nameErr != nil {
103- return "" , errors .Wrapf (nameErr , "failed to extract message name from %s" , path )
96+ func DefaultSubjectNamingStrategy (subjectPrefix string , proto protoFile , protoSchemaSet ProtoSchemaSet ) (string , error ) {
97+ packageName , packageErr := extractPackageNameWithRegex ( proto . Content )
98+ if packageErr != nil {
99+ return "" , errors .Wrapf (packageErr , "failed to extract package name from %s" , proto . Path )
104100 }
105- return protoSchemaSet .Repository + "." + messageName , nil
106- }
107101
108- // TODO once we have single source of truth for the relationship between protos and subjects, we need to modify this function
109- func ChainlinkProtosSubjectNamingStrategy (path , source string , protoSchemaSet ProtoSchemaSet ) (string , error ) {
110- messageName , nameErr := extractTopLevelMessageNamesWithRegex (source )
102+ messageNames , nameErr := extractTopLevelMessageNamesWithRegex (proto .Content )
111103 if nameErr != nil {
112- return "" , errors .Wrapf (nameErr , "failed to extract message name from %s" , path )
104+ return "" , errors .Wrapf (nameErr , "failed to extract message name from %s" , proto . Path )
113105 }
106+ messageName := messageNames [0 ]
114107
115- // this only covers BaseMessage
116- if strings .HasPrefix (path , "common" ) {
117- return "cre-pb." + messageName , nil
108+ return subjectPrefix + packageName + "." + messageName , nil
109+ }
110+
111+ // extractPackageNameWithRegex extracts the package name from a proto source file using regex.
112+ // It returns an error if no package name is found.
113+ func extractPackageNameWithRegex (protoSrc string ) (string , error ) {
114+ matches := regexp .MustCompile (`(?m)^\s*package\s+([a-zA-Z0-9.]+)\s*;` ).FindStringSubmatch (protoSrc )
115+ if len (matches ) < 2 {
116+ return "" , fmt .Errorf ("no package name found in proto source" )
118117 }
119118
120- // this covers all other protos we currently have in the chainlink-protos repo
121- subject := "cre-workflows."
122- pathSplit := strings .Split (path , "/" )
123- if len (pathSplit ) > 1 {
124- for _ , part := range pathSplit {
125- matches := regexp .MustCompile (`v[0-9]+` ).FindAllStringSubmatch (part , - 1 )
126- if len (matches ) > 0 {
127- subject += matches [0 ][0 ]
128- }
129- }
130- } else {
131- return "" , fmt .Errorf ("no subject found for %s" , path )
119+ if matches [1 ] == "" {
120+ return "" , fmt .Errorf ("empty package name found in proto source" )
132121 }
133122
134- return subject + "." + messageName , nil
123+ return matches [ 1 ] , nil
135124}
136125
137126// we use simple regex to extract top-level message names from a proto file
138127// so that we don't need to parse the proto file with a parser (which would require a lot of dependencies)
139- func extractTopLevelMessageNamesWithRegex (protoSrc string ) (string , error ) {
128+ func extractTopLevelMessageNamesWithRegex (protoSrc string ) ([] string , error ) {
140129 matches := regexp .MustCompile (`(?m)^\s*message\s+(\w+)\s*{` ).FindAllStringSubmatch (protoSrc , - 1 )
141130 var names []string
142131 for _ , match := range matches {
@@ -146,11 +135,10 @@ func extractTopLevelMessageNamesWithRegex(protoSrc string) (string, error) {
146135 }
147136
148137 if len (names ) == 0 {
149- return "" , fmt .Errorf ("no message names found in %s" , protoSrc )
138+ return nil , fmt .Errorf ("no message names found in %s" , protoSrc )
150139 }
151140
152- // even though there could be more than 1 message in a single proto, we still need to register all of them under one subject
153- return names [0 ], nil
141+ return names , nil
154142}
155143
156144// Fetches .proto files from a GitHub repo optionally scoped to specific folders. It is recommended to use `*github.Client` with auth token to avoid rate limiting.
@@ -280,10 +268,12 @@ func registerAllWithTopologicalSortingByTrial(
280268 continue
281269 }
282270
271+ singleProtoFailures := []error {}
283272 framework .L .Debug ().Msgf ("🔄 registering %s as %s" , path , subject )
284273 _ , registerErr := registerSingleProto (schemaRegistryURL , subject , schema .Source , refs )
285274 if registerErr != nil {
286275 failures = append (failures , fmt .Sprintf ("%s: %v" , path , registerErr ))
276+ singleProtoFailures = append (singleProtoFailures , registerErr )
287277 continue
288278 }
289279
@@ -296,6 +286,7 @@ func registerAllWithTopologicalSortingByTrial(
296286 })
297287
298288 framework .L .Info ().Msgf ("✔ registered: %s as %s" , path , subject )
289+
299290 progress = true
300291 }
301292
0 commit comments