@@ -26,6 +26,7 @@ import (
26
26
"github.com/rs/zerolog"
27
27
"google.golang.org/grpc/codes"
28
28
"google.golang.org/grpc/status"
29
+ "google.golang.org/protobuf/types/known/structpb"
29
30
30
31
"github.com/stacklok/minder/internal/db"
31
32
"github.com/stacklok/minder/internal/engine/engcontext"
@@ -56,32 +57,30 @@ func (s *Server) RegisterRepository(
56
57
projectID := GetProjectID (ctx )
57
58
providerName := GetProviderName (ctx )
58
59
59
- // Validate that the Repository struct in the request
60
- githubRepo := in .GetRepository ()
61
- // If the repo owner is missing, GitHub will assume a default value based
62
- // on the user's credentials. An explicit check for owner is left out to
63
- // avoid breaking backwards compatibility.
64
- if githubRepo .GetName () == "" {
65
- return nil , util .UserVisibleError (codes .InvalidArgument , "missing repository name" )
60
+ var fetchByProps * properties.Properties
61
+ var provider * db.Provider
62
+ var err error
63
+ if in .GetEntity () != nil {
64
+ fetchByProps , provider , err = s .repoCreateInfoFromUpstreamEntityRef (
65
+ ctx , projectID , providerName , in .GetEntity ())
66
+ } else if in .GetRepository () != nil {
67
+ fetchByProps , provider , err = s .repoCreateInfoFromUpstreamRepositoryRef (
68
+ ctx , projectID , providerName , in .GetRepository ())
69
+ } else {
70
+ return nil , util .UserVisibleError (codes .InvalidArgument , "missing entity or repository field" )
71
+ }
72
+
73
+ if err != nil {
74
+ return nil , err
66
75
}
67
76
68
77
l := zerolog .Ctx (ctx ).With ().
69
- Str ("repoName" , githubRepo .GetName ()).
70
- Str ("repoOwner" , githubRepo .GetOwner ()).
78
+ Dict ("properties" , fetchByProps .ToLogDict ()).
71
79
Str ("projectID" , projectID .String ()).
72
80
Logger ()
73
81
ctx = l .WithContext (ctx )
74
82
75
- provider , err := s .inferProviderByOwner (ctx , githubRepo .GetOwner (), projectID , providerName )
76
- if err != nil {
77
- pErr := providers.ErrProviderNotFoundBy {}
78
- if errors .As (err , & pErr ) {
79
- return nil , util .UserVisibleError (codes .NotFound , "no suitable provider found, please enroll a provider" )
80
- }
81
- return nil , status .Errorf (codes .Internal , "cannot get provider: %v" , err )
82
- }
83
-
84
- newRepo , err := s .repos .CreateRepository (ctx , provider , projectID , githubRepo .GetOwner (), githubRepo .GetName ())
83
+ newRepo , err := s .repos .CreateRepository (ctx , provider , projectID , fetchByProps )
85
84
if err != nil {
86
85
if errors .Is (err , repositories .ErrPrivateRepoForbidden ) || errors .Is (err , repositories .ErrArchivedRepoForbidden ) {
87
86
return nil , util .UserVisibleError (codes .InvalidArgument , "%s" , err .Error ())
@@ -99,6 +98,62 @@ func (s *Server) RegisterRepository(
99
98
}, nil
100
99
}
101
100
101
+ func (s * Server ) repoCreateInfoFromUpstreamRepositoryRef (
102
+ ctx context.Context ,
103
+ projectID uuid.UUID ,
104
+ providerName string ,
105
+ rep * pb.UpstreamRepositoryRef ,
106
+ ) (* properties.Properties , * db.Provider , error ) {
107
+ // If the repo owner is missing, GitHub will assume a default value based
108
+ // on the user's credentials. An explicit check for owner is left out to
109
+ // avoid breaking backwards compatibility.
110
+ if rep .GetName () == "" {
111
+ return nil , nil , util .UserVisibleError (codes .InvalidArgument , "missing repository name" )
112
+ }
113
+
114
+ fetchByProps , err := properties .NewProperties (map [string ]any {
115
+ properties .PropertyUpstreamID : fmt .Sprintf ("%d" , rep .GetRepoId ()),
116
+ properties .PropertyName : fmt .Sprintf ("%s/%s" , rep .GetOwner (), rep .GetName ()),
117
+ })
118
+ if err != nil {
119
+ return nil , nil , fmt .Errorf ("error creating properties: %w" , err )
120
+ }
121
+
122
+ provider , err := s .inferProviderByOwner (ctx , rep .GetOwner (), projectID , providerName )
123
+ if err != nil {
124
+ pErr := providers.ErrProviderNotFoundBy {}
125
+ if errors .As (err , & pErr ) {
126
+ return nil , nil , util .UserVisibleError (codes .NotFound , "no suitable provider found, please enroll a provider" )
127
+ }
128
+ return nil , nil , status .Errorf (codes .Internal , "cannot get provider: %v" , err )
129
+ }
130
+
131
+ return fetchByProps , provider , nil
132
+ }
133
+
134
+ func (s * Server ) repoCreateInfoFromUpstreamEntityRef (
135
+ ctx context.Context ,
136
+ projectID uuid.UUID ,
137
+ providerName string ,
138
+ entity * pb.UpstreamEntityRef ,
139
+ ) (* properties.Properties , * db.Provider , error ) {
140
+ inPropsMap := entity .GetProperties ().AsMap ()
141
+ fetchByProps , err := properties .NewProperties (inPropsMap )
142
+ if err != nil {
143
+ return nil , nil , fmt .Errorf ("error creating properties: %w" , err )
144
+ }
145
+
146
+ provider , err := s .providerStore .GetByName (ctx , projectID , providerName )
147
+ if err != nil {
148
+ if errors .Is (err , sql .ErrNoRows ) {
149
+ return nil , nil , util .UserVisibleError (codes .NotFound , "provider not found" )
150
+ }
151
+ return nil , nil , status .Errorf (codes .Internal , "cannot get provider: %v" , err )
152
+ }
153
+
154
+ return fetchByProps , provider , nil
155
+ }
156
+
102
157
// ListRepositories returns a list of repositories for a given project
103
158
// This function will typically be called by the client to get a list of
104
159
// repositories that are registered present in the minder database
@@ -330,7 +385,8 @@ func (s *Server) ListRemoteRepositoriesFromProvider(
330
385
}
331
386
332
387
out := & pb.ListRemoteRepositoriesFromProviderResponse {
333
- Results : []* pb.UpstreamRepositoryRef {},
388
+ Results : []* pb.UpstreamRepositoryRef {},
389
+ Entities : []* pb.RegistrableUpstreamEntityRef {},
334
390
}
335
391
336
392
for providerID , providerT := range provs {
@@ -342,7 +398,10 @@ func (s *Server) ListRemoteRepositoriesFromProvider(
342
398
errorProvs = append (errorProvs , providerT .Name )
343
399
continue
344
400
}
345
- out .Results = append (out .Results , results ... )
401
+ for _ , result := range results {
402
+ out .Results = append (out .Results , result .Repo )
403
+ out .Entities = append (out .Entities , result .Entity )
404
+ }
346
405
}
347
406
348
407
// If all providers failed, return an error
@@ -362,7 +421,7 @@ func (s *Server) fetchRepositoriesForProvider(
362
421
providerID uuid.UUID ,
363
422
providerName string ,
364
423
provider v1.Provider ,
365
- ) ([]* pb. UpstreamRepositoryRef , error ) {
424
+ ) ([]* UpstreamRepoAndEntityRef , error ) {
366
425
zerolog .Ctx (ctx ).Trace ().
367
426
Str ("provider_id" , providerID .String ()).
368
427
Str ("project_id" , projectID .String ()).
@@ -412,10 +471,35 @@ func (s *Server) fetchRepositoriesForProvider(
412
471
}
413
472
414
473
for _ , result := range results {
415
- // TEMPORARY: This will be changed to use properties.
416
- // for now, we transform the repo ID to a string
417
- uid := fmt .Sprintf ("%d" , result .RepoId )
418
- result .Registered = registered [uid ]
474
+ uprops := result .Entity .GetEntity ().GetProperties ()
475
+ upropsMap := uprops .AsMap ()
476
+ if upropsMap == nil {
477
+ zerolog .Ctx (ctx ).Warn ().
478
+ Str ("provider_id" , providerID .String ()).
479
+ Str ("project_id" , projectID .String ()).
480
+ Msg ("upstream repository entry has no properties" )
481
+ continue
482
+ }
483
+ uidAny , ok := upropsMap [properties .PropertyUpstreamID ]
484
+ if ! ok {
485
+ zerolog .Ctx (ctx ).Warn ().
486
+ Str ("provider_id" , providerID .String ()).
487
+ Str ("project_id" , projectID .String ()).
488
+ Msg ("upstream repository entry has no upstream ID" )
489
+ continue
490
+ }
491
+
492
+ uid , ok := uidAny .(string )
493
+ if ! ok {
494
+ zerolog .Ctx (ctx ).Warn ().
495
+ Str ("provider_id" , providerID .String ()).
496
+ Str ("project_id" , projectID .String ()).
497
+ Msg ("upstream repository entry has invalid upstream ID" )
498
+ continue
499
+ }
500
+
501
+ result .Repo .Registered = registered [uid ]
502
+ result .Entity .Registered = registered [uid ]
419
503
}
420
504
421
505
return results , nil
@@ -426,7 +510,7 @@ func (s *Server) listRemoteRepositoriesForProvider(
426
510
provName string ,
427
511
repoLister v1.RepoLister ,
428
512
projectID uuid.UUID ,
429
- ) ([]* pb. UpstreamRepositoryRef , error ) {
513
+ ) ([]* UpstreamRepoAndEntityRef , error ) {
430
514
tmoutCtx , cancel := context .WithTimeout (ctx , github .ExpensiveRestCallTimeout )
431
515
defer cancel ()
432
516
@@ -442,22 +526,40 @@ func (s *Server) listRemoteRepositoriesForProvider(
442
526
zerolog .Ctx (ctx ).Info ().Msg ("including private repositories" )
443
527
}
444
528
445
- results := make ([]* pb. UpstreamRepositoryRef , 0 , len (remoteRepos ))
529
+ results := make ([]* UpstreamRepoAndEntityRef , 0 , len (remoteRepos ))
446
530
447
531
for idx , rem := range remoteRepos {
448
532
// Skip private repositories
449
533
if rem .IsPrivate && ! allowsPrivateRepos {
450
534
continue
451
535
}
452
536
remoteRepo := remoteRepos [idx ]
453
- repo := & pb.UpstreamRepositoryRef {
454
- Context : & pb.Context {
455
- Provider : & provName ,
456
- Project : ptr .Ptr (projectID .String ()),
537
+
538
+ var props * structpb.Struct
539
+ if remoteRepo .Properties != nil {
540
+ props = remoteRepo .Properties
541
+ }
542
+
543
+ repo := & UpstreamRepoAndEntityRef {
544
+ Repo : & pb.UpstreamRepositoryRef {
545
+ Context : & pb.Context {
546
+ Provider : & provName ,
547
+ Project : ptr .Ptr (projectID .String ()),
548
+ },
549
+ Owner : remoteRepo .Owner ,
550
+ Name : remoteRepo .Name ,
551
+ RepoId : remoteRepo .RepoId ,
552
+ },
553
+ Entity : & pb.RegistrableUpstreamEntityRef {
554
+ Entity : & pb.UpstreamEntityRef {
555
+ Context : & pb.ContextV2 {
556
+ Provider : provName ,
557
+ ProjectId : projectID .String (),
558
+ },
559
+ Type : pb .Entity_ENTITY_REPOSITORIES ,
560
+ Properties : props ,
561
+ },
457
562
},
458
- Owner : remoteRepo .Owner ,
459
- Name : remoteRepo .Name ,
460
- RepoId : remoteRepo .RepoId ,
461
563
}
462
564
results = append (results , repo )
463
565
}
@@ -496,3 +598,9 @@ func (s *Server) inferProviderByOwner(ctx context.Context, owner string, project
496
598
497
599
return nil , fmt .Errorf ("no providers can handle repo owned by %s" , owner )
498
600
}
601
+
602
+ // UpstreamRepoAndEntityRef is a pair of upstream repository and entity references
603
+ type UpstreamRepoAndEntityRef struct {
604
+ Repo * pb.UpstreamRepositoryRef
605
+ Entity * pb.RegistrableUpstreamEntityRef
606
+ }
0 commit comments