diff --git a/.local-dev/config/ns.yaml b/.local-dev/config/ns.yaml index d44f31e77..fe59ed114 100644 --- a/.local-dev/config/ns.yaml +++ b/.local-dev/config/ns.yaml @@ -124,7 +124,8 @@ components: giteaIntegration: url: https://git.trap.jp token: "" - intervalSeconds: 600 + controller: + url: http://ns-controller:10000 ssgen: artifactsRoot: /artifacts diff --git a/.local-dev/manifest/ns-system/config/ns.yaml b/.local-dev/manifest/ns-system/config/ns.yaml index 5a4e65029..5ae2732a8 100644 --- a/.local-dev/manifest/ns-system/config/ns.yaml +++ b/.local-dev/manifest/ns-system/config/ns.yaml @@ -139,6 +139,12 @@ components: container_memory_usage_bytes{namespace="ns-apps", pod="nsapp-{{ .App.ID }}-0", container="app"} + container_memory_swap{namespace="ns-apps", pod="nsapp-{{ .App.ID }}-0", container="app"} + giteaIntegration: + url: https://git.trap.jp + token: "" + controller: + url: http://ns-controller:10000 + ssgen: artifactsRoot: /artifacts healthPort: 8081 diff --git a/api/proto/neoshowcase/protobuf/controller.proto b/api/proto/neoshowcase/protobuf/controller.proto index 1a8461b6a..ecdbee300 100644 --- a/api/proto/neoshowcase/protobuf/controller.proto +++ b/api/proto/neoshowcase/protobuf/controller.proto @@ -68,6 +68,13 @@ message SSGenRequest { Type type = 1; } +message GiteaIntegrationRequest { + enum Type { + RESYNC = 0; + } + Type type = 1; +} + service ControllerService { rpc GetSystemInfo(google.protobuf.Empty) returns (SystemInfo); @@ -85,3 +92,7 @@ service ControllerBuilderService { service ControllerSSGenService { rpc ConnectSSGen(google.protobuf.Empty) returns (stream SSGenRequest); } + +service ControllerGiteaIntegrationService { + rpc Connect(google.protobuf.Empty) returns (stream GiteaIntegrationRequest); +} diff --git a/cmd/config.go b/cmd/config.go index 5baeddb48..08ea2181f 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -88,10 +88,11 @@ type GatewayConfig struct { } type GiteaIntegrationConfig struct { - URL string `mapstructure:"url" yaml:"url"` - Token string `mapstructure:"token" yaml:"token"` - IntervalSeconds int `mapstructure:"intervalSeconds" yaml:"intervalSeconds"` - ListIntervalMs int `mapstructure:"listIntervalMs" yaml:"listIntervalMs"` + URL string `mapstructure:"url" yaml:"url"` + Token string `mapstructure:"token" yaml:"token"` + IntervalSeconds int `mapstructure:"intervalSeconds" yaml:"intervalSeconds"` + Concurrency int `mapstructure:"concurrency" yaml:"concurrency"` + Controller grpc.ControllerServiceClientConfig `mapstructure:"controller" yaml:"controller"` } type SSGenConfig struct { @@ -237,8 +238,9 @@ func init() { viper.SetDefault("components.giteaIntegration.url", "https://git.trap.jp") viper.SetDefault("components.giteaIntegration.token", "") - viper.SetDefault("components.giteaIntegration.intervalSeconds", 600) - viper.SetDefault("components.giteaIntegration.listIntervalMs", 250) + viper.SetDefault("components.giteaIntegration.intervalSeconds", 86400) + viper.SetDefault("components.giteaIntegration.concurrency", 10) + viper.SetDefault("components.giteaIntegration.controller.url", "http://ns-controller:10000") viper.SetDefault("components.ssgen.artifactsRoot", "/srv/artifacts") viper.SetDefault("components.ssgen.healthPort", 8081) diff --git a/cmd/providers.go b/cmd/providers.go index 5837f8978..8465c873e 100644 --- a/cmd/providers.go +++ b/cmd/providers.go @@ -67,6 +67,8 @@ var providers = wire.NewSet( grpc.NewControllerService, grpc.NewControllerServiceClient, grpc.NewControllerBuilderService, + grpc.NewControllerGiteaIntegrationService, + grpc.NewControllerGiteaIntegrationServiceClient, provideControllerBuilderServiceClient, grpc.NewControllerSSGenService, grpc.NewControllerSSGenServiceClient, @@ -92,7 +94,7 @@ var providers = wire.NewSet( provideStorage, provideAuthDevServer, provideBuildpackBackend, - provdeBuildkitClient, + provideBuildkitClient, provideControllerServer, provideContainerLogger, provideMetricsService, @@ -150,7 +152,7 @@ func provideBuildpackBackend(c Config) (builder.BuildpackBackend, error) { } } -func provdeBuildkitClient(c Config) (*buildkit.Client, error) { +func provideBuildkitClient(c Config) (*buildkit.Client, error) { cc := c.Components.Builder ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() @@ -166,6 +168,7 @@ func provideControllerServer( controllerHandler pbconnect.ControllerServiceHandler, builderHandler domain.ControllerBuilderService, ssgenHandler domain.ControllerSSGenService, + giteaIntegrationHandler domain.ControllerGiteaIntegrationService, ) *controller.APIServer { wc := web.H2CConfig{ Port: c.Components.Controller.Port, @@ -173,6 +176,7 @@ func provideControllerServer( mux.Handle(pbconnect.NewControllerServiceHandler(controllerHandler)) mux.Handle(pbconnect.NewControllerBuilderServiceHandler(builderHandler)) mux.Handle(pbconnect.NewControllerSSGenServiceHandler(ssgenHandler)) + mux.Handle(pbconnect.NewControllerGiteaIntegrationServiceHandler(giteaIntegrationHandler)) }, } return &controller.APIServer{H2CServer: web.NewH2CServer(wc)} @@ -221,7 +225,7 @@ func provideGiteaIntegrationConfig(c Config) giteaintegration.Config { URL: cc.URL, Token: cc.Token, IntervalSeconds: cc.IntervalSeconds, - ListIntervalMs: cc.ListIntervalMs, + Concurrency: cc.Concurrency, } } diff --git a/cmd/wire.go b/cmd/wire.go index 8f860ceeb..de120b80e 100644 --- a/cmd/wire.go +++ b/cmd/wire.go @@ -80,6 +80,7 @@ func NewGateway(c Config) (component, error) { func NewGiteaIntegration(c Config) (component, error) { wire.Build( providers, + wire.FieldsOf(new(GiteaIntegrationConfig), "Controller"), wire.Bind(new(component), new(*giteaintegration.Server)), wire.Struct(new(giteaintegration.Server), "*"), ) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 90956d883..b945fa338 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -52,7 +52,7 @@ func NewBuilder(c Config) (component, error) { if err != nil { return nil, err } - client, err := provdeBuildkitClient(c) + client, err := provideBuildkitClient(c) if err != nil { return nil, err } @@ -130,11 +130,12 @@ func NewControllerDocker(c Config) (component, error) { sshConfig := controllerConfig.SSH adminerURL := c.AdminerURL controllerServiceHandler := grpc.NewControllerService(backend, applicationRepository, repofetcherService, cdserviceService, controllerBuilderService, service, publicKeys, sshConfig, adminerURL) - apiServer := provideControllerServer(c, controllerServiceHandler, controllerBuilderService, controllerSSGenService) + controllerGiteaIntegrationService := grpc.NewControllerGiteaIntegrationService() + apiServer := provideControllerServer(c, controllerServiceHandler, controllerBuilderService, controllerSSGenService, controllerGiteaIntegrationService) userRepository := repository.NewUserRepository(db) sshServer := sshserver.NewSSHServer(sshConfig, publicKeys, backend, applicationRepository, userRepository) receiverConfig := controllerConfig.Webhook - receiver := webhook.NewReceiver(receiverConfig, gitRepositoryRepository, repofetcherService) + receiver := webhook.NewReceiver(receiverConfig, gitRepositoryRepository, repofetcherService, controllerGiteaIntegrationService) artifactRepository := repository.NewArtifactRepository(db) storageConfig := c.Storage storage, err := provideStorage(storageConfig) @@ -212,11 +213,12 @@ func NewControllerK8s(c Config) (component, error) { sshConfig := controllerConfig.SSH adminerURL := c.AdminerURL controllerServiceHandler := grpc.NewControllerService(backend, applicationRepository, repofetcherService, cdserviceService, controllerBuilderService, service, publicKeys, sshConfig, adminerURL) - apiServer := provideControllerServer(c, controllerServiceHandler, controllerBuilderService, controllerSSGenService) + controllerGiteaIntegrationService := grpc.NewControllerGiteaIntegrationService() + apiServer := provideControllerServer(c, controllerServiceHandler, controllerBuilderService, controllerSSGenService, controllerGiteaIntegrationService) userRepository := repository.NewUserRepository(db) sshServer := sshserver.NewSSHServer(sshConfig, publicKeys, backend, applicationRepository, userRepository) receiverConfig := controllerConfig.Webhook - receiver := webhook.NewReceiver(receiverConfig, gitRepositoryRepository, repofetcherService) + receiver := webhook.NewReceiver(receiverConfig, gitRepositoryRepository, repofetcherService, controllerGiteaIntegrationService) artifactRepository := repository.NewArtifactRepository(db) storageConfig := c.Storage storage, err := provideStorage(storageConfig) @@ -302,6 +304,10 @@ func NewGateway(c Config) (component, error) { func NewGiteaIntegration(c Config) (component, error) { giteaintegrationConfig := provideGiteaIntegrationConfig(c) + componentsConfig := c.Components + giteaIntegrationConfig := componentsConfig.GiteaIntegration + controllerServiceClientConfig := giteaIntegrationConfig.Controller + controllerGiteaIntegrationServiceClient := grpc.NewControllerGiteaIntegrationServiceClient(controllerServiceClientConfig) repositoryConfig := c.DB db, err := repository.New(repositoryConfig) if err != nil { @@ -310,7 +316,7 @@ func NewGiteaIntegration(c Config) (component, error) { gitRepositoryRepository := repository.NewGitRepositoryRepository(db) applicationRepository := repository.NewApplicationRepository(db) userRepository := repository.NewUserRepository(db) - integration, err := giteaintegration.NewIntegration(giteaintegrationConfig, gitRepositoryRepository, applicationRepository, userRepository) + integration, err := giteaintegration.NewIntegration(giteaintegrationConfig, controllerGiteaIntegrationServiceClient, gitRepositoryRepository, applicationRepository, userRepository) if err != nil { return nil, err } diff --git a/compose.yaml b/compose.yaml index cf7c739b8..c42f293fc 100644 --- a/compose.yaml +++ b/compose.yaml @@ -84,7 +84,7 @@ services: # context: . # target: ns-gitea-integration # image: ghcr.io/traptitech/ns-gitea-integration:main -# command: --debug --loglevel=trace --config=/config.yaml +# command: --config=/config.yaml # restart: always # volumes: # - ./.local-dev/config/ns.yaml:/config.yaml diff --git a/pkg/domain/component.go b/pkg/domain/component.go index 0d9497cf4..0476406cd 100644 --- a/pkg/domain/component.go +++ b/pkg/domain/component.go @@ -51,3 +51,12 @@ type ControllerSSGenService interface { type ControllerSSGenServiceClient interface { ConnectSSGen(ctx context.Context, onRequest func(req *pb.SSGenRequest)) error } + +type ControllerGiteaIntegrationService interface { + pbconnect.ControllerGiteaIntegrationServiceHandler + Broadcast(req *pb.GiteaIntegrationRequest) +} + +type ControllerGiteaIntegrationServiceClient interface { + Connect(ctx context.Context, onRequest func(req *pb.GiteaIntegrationRequest)) error +} diff --git a/pkg/infrastructure/grpc/controller_gitea_integration_service.go b/pkg/infrastructure/grpc/controller_gitea_integration_service.go new file mode 100644 index 000000000..98cc30af9 --- /dev/null +++ b/pkg/infrastructure/grpc/controller_gitea_integration_service.go @@ -0,0 +1,75 @@ +package grpc + +import ( + "context" + "sync" + + "connectrpc.com/connect" + "github.com/samber/lo" + log "github.com/sirupsen/logrus" + "google.golang.org/protobuf/types/known/emptypb" + + "github.com/traPtitech/neoshowcase/pkg/domain" + "github.com/traPtitech/neoshowcase/pkg/infrastructure/grpc/pb" +) + +type giteaIntegrationConnection struct { + reqSender chan<- *pb.GiteaIntegrationRequest +} + +type ControllerGiteaIntegrationService struct { + connections []*giteaIntegrationConnection + lock sync.Mutex +} + +func NewControllerGiteaIntegrationService() domain.ControllerGiteaIntegrationService { + return &ControllerGiteaIntegrationService{} +} + +func (s *ControllerGiteaIntegrationService) Connect(ctx context.Context, _ *connect.Request[emptypb.Empty], st *connect.ServerStream[pb.GiteaIntegrationRequest]) error { + id := domain.NewID() + log.WithField("id", id).Info("new gitea integration connection") + defer log.WithField("id", id).Info("gitea integration connection closed") + + reqSender := make(chan *pb.GiteaIntegrationRequest) + conn := &giteaIntegrationConnection{reqSender: reqSender} + s.lock.Lock() + s.connections = append(s.connections, conn) + s.lock.Unlock() + + defer func() { + s.lock.Lock() + defer s.lock.Unlock() + s.connections = lo.Without(s.connections, conn) + }() + +loop: + for { + select { + case req, ok := <-reqSender: + if !ok { + break loop + } + err := st.Send(req) + if err != nil { + return err + } + case <-ctx.Done(): + break loop + } + } + + return nil +} + +func (s *ControllerGiteaIntegrationService) Broadcast(req *pb.GiteaIntegrationRequest) { + s.lock.Lock() + defer s.lock.Unlock() + + for _, ssgen := range s.connections { + select { + case ssgen.reqSender <- req: + default: + } + } +} diff --git a/pkg/infrastructure/grpc/controller_gitea_integration_service_client.go b/pkg/infrastructure/grpc/controller_gitea_integration_service_client.go new file mode 100644 index 000000000..072ef66fd --- /dev/null +++ b/pkg/infrastructure/grpc/controller_gitea_integration_service_client.go @@ -0,0 +1,42 @@ +package grpc + +import ( + "context" + + "connectrpc.com/connect" + "google.golang.org/protobuf/types/known/emptypb" + + "github.com/traPtitech/neoshowcase/pkg/domain" + "github.com/traPtitech/neoshowcase/pkg/domain/web" + "github.com/traPtitech/neoshowcase/pkg/infrastructure/grpc/pb" + "github.com/traPtitech/neoshowcase/pkg/infrastructure/grpc/pb/pbconnect" +) + +type ControllerGiteaIntegrationServiceClient struct { + client pbconnect.ControllerGiteaIntegrationServiceClient +} + +func NewControllerGiteaIntegrationServiceClient( + c ControllerServiceClientConfig, +) domain.ControllerGiteaIntegrationServiceClient { + return &ControllerGiteaIntegrationServiceClient{ + client: pbconnect.NewControllerGiteaIntegrationServiceClient(web.NewH2CClient(), c.URL), + } +} + +func (c *ControllerGiteaIntegrationServiceClient) Connect(ctx context.Context, onRequest func(req *pb.GiteaIntegrationRequest)) error { + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + st, err := c.client.Connect(ctx, connect.NewRequest(&emptypb.Empty{})) + if err != nil { + return err + } + defer st.Close() + + for st.Receive() { + msg := st.Msg() + onRequest(msg) + } + return st.Err() +} diff --git a/pkg/infrastructure/grpc/pb/controller.pb.go b/pkg/infrastructure/grpc/pb/controller.pb.go index 508875389..6857bd208 100644 --- a/pkg/infrastructure/grpc/pb/controller.pb.go +++ b/pkg/infrastructure/grpc/pb/controller.pb.go @@ -211,6 +211,49 @@ func (SSGenRequest_Type) EnumDescriptor() ([]byte, []int) { return file_neoshowcase_protobuf_controller_proto_rawDescGZIP(), []int{7, 0} } +type GiteaIntegrationRequest_Type int32 + +const ( + GiteaIntegrationRequest_RESYNC GiteaIntegrationRequest_Type = 0 +) + +// Enum value maps for GiteaIntegrationRequest_Type. +var ( + GiteaIntegrationRequest_Type_name = map[int32]string{ + 0: "RESYNC", + } + GiteaIntegrationRequest_Type_value = map[string]int32{ + "RESYNC": 0, + } +) + +func (x GiteaIntegrationRequest_Type) Enum() *GiteaIntegrationRequest_Type { + p := new(GiteaIntegrationRequest_Type) + *p = x + return p +} + +func (x GiteaIntegrationRequest_Type) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GiteaIntegrationRequest_Type) Descriptor() protoreflect.EnumDescriptor { + return file_neoshowcase_protobuf_controller_proto_enumTypes[4].Descriptor() +} + +func (GiteaIntegrationRequest_Type) Type() protoreflect.EnumType { + return &file_neoshowcase_protobuf_controller_proto_enumTypes[4] +} + +func (x GiteaIntegrationRequest_Type) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GiteaIntegrationRequest_Type.Descriptor instead. +func (GiteaIntegrationRequest_Type) EnumDescriptor() ([]byte, []int) { + return file_neoshowcase_protobuf_controller_proto_rawDescGZIP(), []int{8, 0} +} + type StartBuildRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -716,6 +759,53 @@ func (x *SSGenRequest) GetType() SSGenRequest_Type { return SSGenRequest_RELOAD } +type GiteaIntegrationRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type GiteaIntegrationRequest_Type `protobuf:"varint,1,opt,name=type,proto3,enum=neoshowcase.protobuf.GiteaIntegrationRequest_Type" json:"type,omitempty"` +} + +func (x *GiteaIntegrationRequest) Reset() { + *x = GiteaIntegrationRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_neoshowcase_protobuf_controller_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GiteaIntegrationRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GiteaIntegrationRequest) ProtoMessage() {} + +func (x *GiteaIntegrationRequest) ProtoReflect() protoreflect.Message { + mi := &file_neoshowcase_protobuf_controller_proto_msgTypes[8] + 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 GiteaIntegrationRequest.ProtoReflect.Descriptor instead. +func (*GiteaIntegrationRequest) Descriptor() ([]byte, []int) { + return file_neoshowcase_protobuf_controller_proto_rawDescGZIP(), []int{8} +} + +func (x *GiteaIntegrationRequest) GetType() GiteaIntegrationRequest_Type { + if x != nil { + return x.Type + } + return GiteaIntegrationRequest_RESYNC +} + var File_neoshowcase_protobuf_controller_proto protoreflect.FileDescriptor var file_neoshowcase_protobuf_controller_proto_rawDesc = []byte{ @@ -799,52 +889,67 @@ var file_neoshowcase_protobuf_controller_proto_rawDesc = []byte{ 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x53, 0x47, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x00, 0x32, 0xf3, 0x03, 0x0a, - 0x11, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x6e, 0x65, + 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4c, 0x4f, 0x41, 0x44, 0x10, 0x00, 0x22, 0x75, 0x0a, 0x17, + 0x47, 0x69, 0x74, 0x65, 0x61, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x46, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, + 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x47, 0x69, 0x74, + 0x65, 0x61, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x12, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x53, 0x59, 0x4e, + 0x43, 0x10, 0x00, 0x32, 0xf3, 0x03, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x47, 0x65, 0x74, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x54, 0x0a, 0x0f, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x29, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, + 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x53, 0x0a, 0x0d, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x2a, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x54, 0x0a, - 0x0f, 0x46, 0x65, 0x74, 0x63, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, - 0x12, 0x29, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, - 0x72, 0x79, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x12, 0x53, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x12, 0x2a, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, - 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x41, 0x0a, 0x0f, 0x53, 0x79, 0x6e, 0x63, - 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x58, 0x0a, 0x0e, 0x53, - 0x74, 0x72, 0x65, 0x61, 0x6d, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4c, 0x6f, 0x67, 0x12, 0x24, 0x2e, - 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x4c, 0x6f, 0x67, 0x30, 0x01, 0x12, 0x4b, 0x0a, 0x0b, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x12, 0x24, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, - 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x75, 0x66, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x41, 0x0a, 0x0f, 0x53, 0x79, 0x6e, 0x63, 0x44, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x32, 0x7d, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, - 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, - 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, - 0x12, 0x25, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x24, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, + 0x74, 0x79, 0x12, 0x58, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x4c, 0x6f, 0x67, 0x12, 0x24, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, + 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6e, 0x65, 0x6f, + 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4c, 0x6f, 0x67, 0x30, 0x01, 0x12, 0x4b, 0x0a, 0x0b, + 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x24, 0x2e, 0x6e, 0x65, + 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x49, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0x7d, 0x0a, 0x18, 0x43, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x25, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, - 0x01, 0x32, 0x66, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, - 0x53, 0x47, 0x65, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x0c, 0x43, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x53, 0x53, 0x47, 0x65, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x53, 0x47, 0x65, 0x6e, + 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x24, + 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x28, 0x01, 0x30, 0x01, 0x32, 0x66, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x53, 0x47, 0x65, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x4c, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x53, 0x53, 0x47, + 0x65, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x6e, 0x65, 0x6f, + 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x53, 0x47, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x30, 0x01, + 0x32, 0x77, 0x0a, 0x21, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x47, 0x69, + 0x74, 0x65, 0x61, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, + 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2d, 0x2e, 0x6e, 0x65, 0x6f, 0x73, 0x68, + 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x47, 0x69, 0x74, 0x65, 0x61, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x30, 0x01, 0x42, 0x3e, 0x5a, 0x3c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x72, 0x61, 0x50, 0x74, 0x69, 0x74, 0x65, 0x63, 0x68, 0x2f, 0x6e, 0x65, 0x6f, 0x73, 0x68, 0x6f, 0x77, 0x63, 0x61, 0x73, 0x65, 0x2f, 0x70, @@ -865,60 +970,65 @@ func file_neoshowcase_protobuf_controller_proto_rawDescGZIP() []byte { return file_neoshowcase_protobuf_controller_proto_rawDescData } -var file_neoshowcase_protobuf_controller_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_neoshowcase_protobuf_controller_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_neoshowcase_protobuf_controller_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_neoshowcase_protobuf_controller_proto_msgTypes = make([]protoimpl.MessageInfo, 9) var file_neoshowcase_protobuf_controller_proto_goTypes = []interface{}{ - (BuilderRequest_Type)(0), // 0: neoshowcase.protobuf.BuilderRequest.Type - (BuildSettled_Reason)(0), // 1: neoshowcase.protobuf.BuildSettled.Reason - (BuilderResponse_Type)(0), // 2: neoshowcase.protobuf.BuilderResponse.Type - (SSGenRequest_Type)(0), // 3: neoshowcase.protobuf.SSGenRequest.Type - (*StartBuildRequest)(nil), // 4: neoshowcase.protobuf.StartBuildRequest - (*BuilderRequest)(nil), // 5: neoshowcase.protobuf.BuilderRequest - (*ConnectedBody)(nil), // 6: neoshowcase.protobuf.ConnectedBody - (*BuildStarted)(nil), // 7: neoshowcase.protobuf.BuildStarted - (*BuildSettled)(nil), // 8: neoshowcase.protobuf.BuildSettled - (*BuildLogPortion)(nil), // 9: neoshowcase.protobuf.BuildLogPortion - (*BuilderResponse)(nil), // 10: neoshowcase.protobuf.BuilderResponse - (*SSGenRequest)(nil), // 11: neoshowcase.protobuf.SSGenRequest - (*BuildIdRequest)(nil), // 12: neoshowcase.protobuf.BuildIdRequest - (*emptypb.Empty)(nil), // 13: google.protobuf.Empty - (*RepositoryIdRequest)(nil), // 14: neoshowcase.protobuf.RepositoryIdRequest - (*ApplicationIdRequest)(nil), // 15: neoshowcase.protobuf.ApplicationIdRequest - (*SystemInfo)(nil), // 16: neoshowcase.protobuf.SystemInfo - (*BuildLog)(nil), // 17: neoshowcase.protobuf.BuildLog + (BuilderRequest_Type)(0), // 0: neoshowcase.protobuf.BuilderRequest.Type + (BuildSettled_Reason)(0), // 1: neoshowcase.protobuf.BuildSettled.Reason + (BuilderResponse_Type)(0), // 2: neoshowcase.protobuf.BuilderResponse.Type + (SSGenRequest_Type)(0), // 3: neoshowcase.protobuf.SSGenRequest.Type + (GiteaIntegrationRequest_Type)(0), // 4: neoshowcase.protobuf.GiteaIntegrationRequest.Type + (*StartBuildRequest)(nil), // 5: neoshowcase.protobuf.StartBuildRequest + (*BuilderRequest)(nil), // 6: neoshowcase.protobuf.BuilderRequest + (*ConnectedBody)(nil), // 7: neoshowcase.protobuf.ConnectedBody + (*BuildStarted)(nil), // 8: neoshowcase.protobuf.BuildStarted + (*BuildSettled)(nil), // 9: neoshowcase.protobuf.BuildSettled + (*BuildLogPortion)(nil), // 10: neoshowcase.protobuf.BuildLogPortion + (*BuilderResponse)(nil), // 11: neoshowcase.protobuf.BuilderResponse + (*SSGenRequest)(nil), // 12: neoshowcase.protobuf.SSGenRequest + (*GiteaIntegrationRequest)(nil), // 13: neoshowcase.protobuf.GiteaIntegrationRequest + (*BuildIdRequest)(nil), // 14: neoshowcase.protobuf.BuildIdRequest + (*emptypb.Empty)(nil), // 15: google.protobuf.Empty + (*RepositoryIdRequest)(nil), // 16: neoshowcase.protobuf.RepositoryIdRequest + (*ApplicationIdRequest)(nil), // 17: neoshowcase.protobuf.ApplicationIdRequest + (*SystemInfo)(nil), // 18: neoshowcase.protobuf.SystemInfo + (*BuildLog)(nil), // 19: neoshowcase.protobuf.BuildLog } var file_neoshowcase_protobuf_controller_proto_depIdxs = []int32{ 0, // 0: neoshowcase.protobuf.BuilderRequest.type:type_name -> neoshowcase.protobuf.BuilderRequest.Type - 4, // 1: neoshowcase.protobuf.BuilderRequest.start_build:type_name -> neoshowcase.protobuf.StartBuildRequest - 12, // 2: neoshowcase.protobuf.BuilderRequest.cancel_build:type_name -> neoshowcase.protobuf.BuildIdRequest + 5, // 1: neoshowcase.protobuf.BuilderRequest.start_build:type_name -> neoshowcase.protobuf.StartBuildRequest + 14, // 2: neoshowcase.protobuf.BuilderRequest.cancel_build:type_name -> neoshowcase.protobuf.BuildIdRequest 1, // 3: neoshowcase.protobuf.BuildSettled.reason:type_name -> neoshowcase.protobuf.BuildSettled.Reason 2, // 4: neoshowcase.protobuf.BuilderResponse.type:type_name -> neoshowcase.protobuf.BuilderResponse.Type - 6, // 5: neoshowcase.protobuf.BuilderResponse.connected:type_name -> neoshowcase.protobuf.ConnectedBody - 7, // 6: neoshowcase.protobuf.BuilderResponse.started:type_name -> neoshowcase.protobuf.BuildStarted - 8, // 7: neoshowcase.protobuf.BuilderResponse.settled:type_name -> neoshowcase.protobuf.BuildSettled - 9, // 8: neoshowcase.protobuf.BuilderResponse.log:type_name -> neoshowcase.protobuf.BuildLogPortion + 7, // 5: neoshowcase.protobuf.BuilderResponse.connected:type_name -> neoshowcase.protobuf.ConnectedBody + 8, // 6: neoshowcase.protobuf.BuilderResponse.started:type_name -> neoshowcase.protobuf.BuildStarted + 9, // 7: neoshowcase.protobuf.BuilderResponse.settled:type_name -> neoshowcase.protobuf.BuildSettled + 10, // 8: neoshowcase.protobuf.BuilderResponse.log:type_name -> neoshowcase.protobuf.BuildLogPortion 3, // 9: neoshowcase.protobuf.SSGenRequest.type:type_name -> neoshowcase.protobuf.SSGenRequest.Type - 13, // 10: neoshowcase.protobuf.ControllerService.GetSystemInfo:input_type -> google.protobuf.Empty - 14, // 11: neoshowcase.protobuf.ControllerService.FetchRepository:input_type -> neoshowcase.protobuf.RepositoryIdRequest - 15, // 12: neoshowcase.protobuf.ControllerService.RegisterBuild:input_type -> neoshowcase.protobuf.ApplicationIdRequest - 13, // 13: neoshowcase.protobuf.ControllerService.SyncDeployments:input_type -> google.protobuf.Empty - 12, // 14: neoshowcase.protobuf.ControllerService.StreamBuildLog:input_type -> neoshowcase.protobuf.BuildIdRequest - 12, // 15: neoshowcase.protobuf.ControllerService.CancelBuild:input_type -> neoshowcase.protobuf.BuildIdRequest - 10, // 16: neoshowcase.protobuf.ControllerBuilderService.ConnectBuilder:input_type -> neoshowcase.protobuf.BuilderResponse - 13, // 17: neoshowcase.protobuf.ControllerSSGenService.ConnectSSGen:input_type -> google.protobuf.Empty - 16, // 18: neoshowcase.protobuf.ControllerService.GetSystemInfo:output_type -> neoshowcase.protobuf.SystemInfo - 13, // 19: neoshowcase.protobuf.ControllerService.FetchRepository:output_type -> google.protobuf.Empty - 13, // 20: neoshowcase.protobuf.ControllerService.RegisterBuild:output_type -> google.protobuf.Empty - 13, // 21: neoshowcase.protobuf.ControllerService.SyncDeployments:output_type -> google.protobuf.Empty - 17, // 22: neoshowcase.protobuf.ControllerService.StreamBuildLog:output_type -> neoshowcase.protobuf.BuildLog - 13, // 23: neoshowcase.protobuf.ControllerService.CancelBuild:output_type -> google.protobuf.Empty - 5, // 24: neoshowcase.protobuf.ControllerBuilderService.ConnectBuilder:output_type -> neoshowcase.protobuf.BuilderRequest - 11, // 25: neoshowcase.protobuf.ControllerSSGenService.ConnectSSGen:output_type -> neoshowcase.protobuf.SSGenRequest - 18, // [18:26] is the sub-list for method output_type - 10, // [10:18] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 4, // 10: neoshowcase.protobuf.GiteaIntegrationRequest.type:type_name -> neoshowcase.protobuf.GiteaIntegrationRequest.Type + 15, // 11: neoshowcase.protobuf.ControllerService.GetSystemInfo:input_type -> google.protobuf.Empty + 16, // 12: neoshowcase.protobuf.ControllerService.FetchRepository:input_type -> neoshowcase.protobuf.RepositoryIdRequest + 17, // 13: neoshowcase.protobuf.ControllerService.RegisterBuild:input_type -> neoshowcase.protobuf.ApplicationIdRequest + 15, // 14: neoshowcase.protobuf.ControllerService.SyncDeployments:input_type -> google.protobuf.Empty + 14, // 15: neoshowcase.protobuf.ControllerService.StreamBuildLog:input_type -> neoshowcase.protobuf.BuildIdRequest + 14, // 16: neoshowcase.protobuf.ControllerService.CancelBuild:input_type -> neoshowcase.protobuf.BuildIdRequest + 11, // 17: neoshowcase.protobuf.ControllerBuilderService.ConnectBuilder:input_type -> neoshowcase.protobuf.BuilderResponse + 15, // 18: neoshowcase.protobuf.ControllerSSGenService.ConnectSSGen:input_type -> google.protobuf.Empty + 15, // 19: neoshowcase.protobuf.ControllerGiteaIntegrationService.Connect:input_type -> google.protobuf.Empty + 18, // 20: neoshowcase.protobuf.ControllerService.GetSystemInfo:output_type -> neoshowcase.protobuf.SystemInfo + 15, // 21: neoshowcase.protobuf.ControllerService.FetchRepository:output_type -> google.protobuf.Empty + 15, // 22: neoshowcase.protobuf.ControllerService.RegisterBuild:output_type -> google.protobuf.Empty + 15, // 23: neoshowcase.protobuf.ControllerService.SyncDeployments:output_type -> google.protobuf.Empty + 19, // 24: neoshowcase.protobuf.ControllerService.StreamBuildLog:output_type -> neoshowcase.protobuf.BuildLog + 15, // 25: neoshowcase.protobuf.ControllerService.CancelBuild:output_type -> google.protobuf.Empty + 6, // 26: neoshowcase.protobuf.ControllerBuilderService.ConnectBuilder:output_type -> neoshowcase.protobuf.BuilderRequest + 12, // 27: neoshowcase.protobuf.ControllerSSGenService.ConnectSSGen:output_type -> neoshowcase.protobuf.SSGenRequest + 13, // 28: neoshowcase.protobuf.ControllerGiteaIntegrationService.Connect:output_type -> neoshowcase.protobuf.GiteaIntegrationRequest + 20, // [20:29] is the sub-list for method output_type + 11, // [11:20] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_neoshowcase_protobuf_controller_proto_init() } @@ -1024,6 +1134,18 @@ func file_neoshowcase_protobuf_controller_proto_init() { return nil } } + file_neoshowcase_protobuf_controller_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GiteaIntegrationRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_neoshowcase_protobuf_controller_proto_msgTypes[1].OneofWrappers = []interface{}{ (*BuilderRequest_StartBuild)(nil), @@ -1040,10 +1162,10 @@ func file_neoshowcase_protobuf_controller_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_neoshowcase_protobuf_controller_proto_rawDesc, - NumEnums: 4, - NumMessages: 8, + NumEnums: 5, + NumMessages: 9, NumExtensions: 0, - NumServices: 3, + NumServices: 4, }, GoTypes: file_neoshowcase_protobuf_controller_proto_goTypes, DependencyIndexes: file_neoshowcase_protobuf_controller_proto_depIdxs, diff --git a/pkg/infrastructure/grpc/pb/pbconnect/controller.connect.go b/pkg/infrastructure/grpc/pb/pbconnect/controller.connect.go index 2d0523432..6c556b3ab 100644 --- a/pkg/infrastructure/grpc/pb/pbconnect/controller.connect.go +++ b/pkg/infrastructure/grpc/pb/pbconnect/controller.connect.go @@ -28,6 +28,9 @@ const ( ControllerBuilderServiceName = "neoshowcase.protobuf.ControllerBuilderService" // ControllerSSGenServiceName is the fully-qualified name of the ControllerSSGenService service. ControllerSSGenServiceName = "neoshowcase.protobuf.ControllerSSGenService" + // ControllerGiteaIntegrationServiceName is the fully-qualified name of the + // ControllerGiteaIntegrationService service. + ControllerGiteaIntegrationServiceName = "neoshowcase.protobuf.ControllerGiteaIntegrationService" ) // These constants are the fully-qualified names of the RPCs defined in this package. They're @@ -62,6 +65,9 @@ const ( // ControllerSSGenServiceConnectSSGenProcedure is the fully-qualified name of the // ControllerSSGenService's ConnectSSGen RPC. ControllerSSGenServiceConnectSSGenProcedure = "/neoshowcase.protobuf.ControllerSSGenService/ConnectSSGen" + // ControllerGiteaIntegrationServiceConnectProcedure is the fully-qualified name of the + // ControllerGiteaIntegrationService's Connect RPC. + ControllerGiteaIntegrationServiceConnectProcedure = "/neoshowcase.protobuf.ControllerGiteaIntegrationService/Connect" ) // ControllerServiceClient is a client for the neoshowcase.protobuf.ControllerService service. @@ -388,3 +394,72 @@ type UnimplementedControllerSSGenServiceHandler struct{} func (UnimplementedControllerSSGenServiceHandler) ConnectSSGen(context.Context, *connect.Request[emptypb.Empty], *connect.ServerStream[pb.SSGenRequest]) error { return connect.NewError(connect.CodeUnimplemented, errors.New("neoshowcase.protobuf.ControllerSSGenService.ConnectSSGen is not implemented")) } + +// ControllerGiteaIntegrationServiceClient is a client for the +// neoshowcase.protobuf.ControllerGiteaIntegrationService service. +type ControllerGiteaIntegrationServiceClient interface { + Connect(context.Context, *connect.Request[emptypb.Empty]) (*connect.ServerStreamForClient[pb.GiteaIntegrationRequest], error) +} + +// NewControllerGiteaIntegrationServiceClient constructs a client for the +// neoshowcase.protobuf.ControllerGiteaIntegrationService service. By default, it uses the Connect +// protocol with the binary Protobuf Codec, asks for gzipped responses, and sends uncompressed +// requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or +// connect.WithGRPCWeb() options. +// +// The URL supplied here should be the base URL for the Connect or gRPC server (for example, +// http://api.acme.com or https://acme.com/grpc). +func NewControllerGiteaIntegrationServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) ControllerGiteaIntegrationServiceClient { + baseURL = strings.TrimRight(baseURL, "/") + return &controllerGiteaIntegrationServiceClient{ + connect: connect.NewClient[emptypb.Empty, pb.GiteaIntegrationRequest]( + httpClient, + baseURL+ControllerGiteaIntegrationServiceConnectProcedure, + opts..., + ), + } +} + +// controllerGiteaIntegrationServiceClient implements ControllerGiteaIntegrationServiceClient. +type controllerGiteaIntegrationServiceClient struct { + connect *connect.Client[emptypb.Empty, pb.GiteaIntegrationRequest] +} + +// Connect calls neoshowcase.protobuf.ControllerGiteaIntegrationService.Connect. +func (c *controllerGiteaIntegrationServiceClient) Connect(ctx context.Context, req *connect.Request[emptypb.Empty]) (*connect.ServerStreamForClient[pb.GiteaIntegrationRequest], error) { + return c.connect.CallServerStream(ctx, req) +} + +// ControllerGiteaIntegrationServiceHandler is an implementation of the +// neoshowcase.protobuf.ControllerGiteaIntegrationService service. +type ControllerGiteaIntegrationServiceHandler interface { + Connect(context.Context, *connect.Request[emptypb.Empty], *connect.ServerStream[pb.GiteaIntegrationRequest]) error +} + +// NewControllerGiteaIntegrationServiceHandler builds an HTTP handler from the service +// implementation. It returns the path on which to mount the handler and the handler itself. +// +// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf +// and JSON codecs. They also support gzip compression. +func NewControllerGiteaIntegrationServiceHandler(svc ControllerGiteaIntegrationServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) { + controllerGiteaIntegrationServiceConnectHandler := connect.NewServerStreamHandler( + ControllerGiteaIntegrationServiceConnectProcedure, + svc.Connect, + opts..., + ) + return "/neoshowcase.protobuf.ControllerGiteaIntegrationService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case ControllerGiteaIntegrationServiceConnectProcedure: + controllerGiteaIntegrationServiceConnectHandler.ServeHTTP(w, r) + default: + http.NotFound(w, r) + } + }) +} + +// UnimplementedControllerGiteaIntegrationServiceHandler returns CodeUnimplemented from all methods. +type UnimplementedControllerGiteaIntegrationServiceHandler struct{} + +func (UnimplementedControllerGiteaIntegrationServiceHandler) Connect(context.Context, *connect.Request[emptypb.Empty], *connect.ServerStream[pb.GiteaIntegrationRequest]) error { + return connect.NewError(connect.CodeUnimplemented, errors.New("neoshowcase.protobuf.ControllerGiteaIntegrationService.Connect is not implemented")) +} diff --git a/pkg/infrastructure/webhook/gitea.go b/pkg/infrastructure/webhook/gitea.go index c06aa0cb0..425f40d40 100644 --- a/pkg/infrastructure/webhook/gitea.go +++ b/pkg/infrastructure/webhook/gitea.go @@ -1,18 +1,21 @@ package webhook import ( + log "github.com/sirupsen/logrus" "net/http" "github.com/friendsofgo/errors" "github.com/go-playground/webhooks/v6/gitea" "github.com/labstack/echo/v4" "github.com/samber/lo" + + "github.com/traPtitech/neoshowcase/pkg/infrastructure/grpc/pb" ) var giteaHook = lo.Must(gitea.New()) func (r *Receiver) giteaHandler(c echo.Context) error { - rawPayload, err := giteaHook.Parse(c.Request(), gitea.PushEvent) + rawPayload, err := giteaHook.Parse(c.Request(), gitea.PushEvent, gitea.RepositoryEvent) if err != nil { return echo.NewHTTPError(http.StatusInternalServerError, err.Error()) } @@ -26,6 +29,11 @@ func (r *Receiver) giteaHandler(c echo.Context) error { p.Repo.CloneURL, // http://localhost:3000/gitea/webhooks.git } go r.updateURLs(urls) + case gitea.RepositoryPayload: + log.Infof("Repository %v event received -> broadcasting to gitea integration", p.Action) + r.giteaIntegration.Broadcast(&pb.GiteaIntegrationRequest{ + Type: pb.GiteaIntegrationRequest_RESYNC, + }) default: return echo.NewHTTPError(http.StatusInternalServerError, errors.New("unsupported payload type")) } diff --git a/pkg/infrastructure/webhook/receiver.go b/pkg/infrastructure/webhook/receiver.go index 1fbe0f7ec..c1d336062 100644 --- a/pkg/infrastructure/webhook/receiver.go +++ b/pkg/infrastructure/webhook/receiver.go @@ -19,9 +19,10 @@ type ReceiverConfig struct { } type Receiver struct { - config ReceiverConfig - gitRepo domain.GitRepositoryRepository - fetcher repofetcher.Service + config ReceiverConfig + gitRepo domain.GitRepositoryRepository + fetcher repofetcher.Service + giteaIntegration domain.ControllerGiteaIntegrationService echo *echo.Echo } @@ -30,11 +31,13 @@ func NewReceiver( config ReceiverConfig, gitRepo domain.GitRepositoryRepository, fetcher repofetcher.Service, + giteaIntegration domain.ControllerGiteaIntegrationService, ) *Receiver { r := &Receiver{ - config: config, - gitRepo: gitRepo, - fetcher: fetcher, + config: config, + gitRepo: gitRepo, + fetcher: fetcher, + giteaIntegration: giteaIntegration, } e := echo.New() diff --git a/pkg/usecase/gitea-integration/integration.go b/pkg/usecase/gitea-integration/integration.go index ce6d82f71..205bcfb66 100644 --- a/pkg/usecase/gitea-integration/integration.go +++ b/pkg/usecase/gitea-integration/integration.go @@ -2,56 +2,66 @@ package giteaintegration import ( "context" - "errors" + "fmt" + log "github.com/sirupsen/logrus" "time" "code.gitea.io/sdk/gitea" "github.com/traPtitech/neoshowcase/pkg/domain" + "github.com/traPtitech/neoshowcase/pkg/infrastructure/grpc/pb" "github.com/traPtitech/neoshowcase/pkg/util/loop" + "github.com/traPtitech/neoshowcase/pkg/util/retry" + "github.com/traPtitech/neoshowcase/pkg/util/scutil" ) type Config struct { URL string Token string IntervalSeconds int - ListIntervalMs int + Concurrency int } func (c *Config) Validate() error { if c.Token == "" { - return errors.New("provide admin gitea token") + return fmt.Errorf("provide admin gitea token (got empty string)") } if c.IntervalSeconds <= 0 { - return errors.New("provide positive interval seconds") + return fmt.Errorf("provide positive interval seconds (got %v)", c.IntervalSeconds) } - if c.ListIntervalMs <= 0 { - return errors.New("provide positive list interval ms") + if c.Concurrency <= 0 { + return fmt.Errorf("provide positive concurrency (got %v)", c.Concurrency) } return nil } type Integration struct { - c *gitea.Client - interval time.Duration - listInterval time.Duration - cancel func() - - gitRepo domain.GitRepositoryRepository - appRepo domain.ApplicationRepository - userRepo domain.UserRepository + c *gitea.Client + interval time.Duration + concurrency int + + controller domain.ControllerGiteaIntegrationServiceClient + gitRepo domain.GitRepositoryRepository + appRepo domain.ApplicationRepository + userRepo domain.UserRepository + + cancel func() + syncer *scutil.Coalescer } func NewIntegration( c Config, + controller domain.ControllerGiteaIntegrationServiceClient, gitRepo domain.GitRepositoryRepository, appRepo domain.ApplicationRepository, userRepo domain.UserRepository, ) (*Integration, error) { + // Validate config if err := c.Validate(); err != nil { return nil, err } + // Generate gitea client client, err := gitea.NewClient( c.URL, gitea.SetToken(c.Token), @@ -61,21 +71,51 @@ func NewIntegration( if err != nil { return nil, err } - return &Integration{ - c: client, - interval: time.Duration(c.IntervalSeconds) * time.Second, - listInterval: time.Duration(c.ListIntervalMs) * time.Millisecond, - - gitRepo: gitRepo, - appRepo: appRepo, - userRepo: userRepo, - }, nil + + i := &Integration{ + c: client, + interval: time.Duration(c.IntervalSeconds) * time.Second, + concurrency: c.Concurrency, + + controller: controller, + gitRepo: gitRepo, + appRepo: appRepo, + userRepo: userRepo, + } + i.syncer = scutil.NewCoalescer(i.syncAndLog) + return i, nil } func (i *Integration) Start() error { ctx, cancel := context.WithCancel(context.Background()) i.cancel = cancel - go loop.Loop(ctx, i.sync, i.interval, true) + + go retry.Do(ctx, func(ctx context.Context) error { + return i.controller.Connect(ctx, i.onRequest(ctx)) + }, "connect to controller") + go loop.Loop(ctx, func(ctx context.Context) { + _ = i.syncer.Do(ctx) + }, i.interval, true) + + return nil +} + +func (i *Integration) onRequest(ctx context.Context) func(req *pb.GiteaIntegrationRequest) { + return func(req *pb.GiteaIntegrationRequest) { + switch req.Type { + case pb.GiteaIntegrationRequest_RESYNC: + go func() { + _ = i.syncer.Do(ctx) + }() + } + } +} + +func (i *Integration) syncAndLog(ctx context.Context) error { + err := i.sync(ctx) + if err != nil { + log.Errorf("failed to sync: %+v", err) + } return nil } diff --git a/pkg/usecase/gitea-integration/sync.go b/pkg/usecase/gitea-integration/sync.go index eab58fd9b..04205bc45 100644 --- a/pkg/usecase/gitea-integration/sync.go +++ b/pkg/usecase/gitea-integration/sync.go @@ -3,6 +3,7 @@ package giteaintegration import ( "context" "fmt" + "golang.org/x/sync/errgroup" "time" "code.gitea.io/sdk/gitea" @@ -16,7 +17,7 @@ import ( "github.com/traPtitech/neoshowcase/pkg/util/optional" ) -func listAllPages[T any](fn func(page, perPage int) ([]T, error), listInterval time.Duration) ([]T, error) { +func listAllPages[T any](fn func(page, perPage int) ([]T, error)) ([]T, error) { items := make([]T, 0) for page := 1; ; page++ { const perPage = 50 // max per page @@ -28,110 +29,81 @@ func listAllPages[T any](fn func(page, perPage int) ([]T, error), listInterval t if len(pageItems) < perPage { break } - time.Sleep(listInterval) } return items, nil } -func (i *Integration) sync(ctx context.Context) { +func (i *Integration) sync(ctx context.Context) error { start := time.Now() - err := i._sync(ctx) - if err != nil { - log.Errorf("failed to sync with gitea: %+v", err) - return - } - log.Infof("Synced with gitea in %v", time.Since(start)) -} + log.Infof("Starting sync ...") + defer func() { + log.Infof("Sync finished in %v.", time.Since(start)) + }() -func (i *Integration) _sync(ctx context.Context) error { // Sync users + log.Infof("Retrieving users from Gitea ...") giteaUsers, err := listAllPages(func(page, perPage int) ([]*gitea.User, error) { users, _, err := i.c.AdminListUsers(gitea.AdminListUsersOptions{ ListOptions: gitea.ListOptions{Page: page, PageSize: perPage}, }) return users, err - }, i.listInterval) + }) if err != nil { return errors.Wrap(err, "listing users") } userNames := ds.Map(giteaUsers, func(user *gitea.User) string { return user.UserName }) - log.Infof("Syncing %v users", len(userNames)) + + log.Infof("Syncing %v users ...", len(userNames)) users, err := i.userRepo.EnsureUsers(ctx, userNames) if err != nil { return err } usersMap := lo.SliceToMap(users, func(user *domain.User) (string, *domain.User) { return user.Name, user }) - - // Sync repositories for each user - for _, user := range users { - giteaRepos, err := listAllPages(func(page, perPage int) ([]*gitea.Repository, error) { - repos, _, err := i.c.ListUserRepos(user.Name, gitea.ListReposOptions{ - ListOptions: gitea.ListOptions{Page: page, PageSize: perPage}, - }) - return repos, err - }, i.listInterval) - if err != nil { - return errors.Wrap(err, "listing user repositories") - } - - for _, giteaRepo := range giteaRepos { - err = i.syncRepository(ctx, user.Name, []string{user.ID}, giteaRepo) - if err != nil { - return errors.Wrap(err, "syncing user repository") - } - } - - time.Sleep(i.listInterval) - } - - // Sync repositories for each org - giteaOrgs, err := listAllPages(func(page, perPage int) ([]*gitea.Organization, error) { - orgs, _, err := i.c.AdminListOrgs(gitea.AdminListOrgsOptions{ - ListOptions: gitea.ListOptions{Page: page, PageSize: perPage}, + log.Infof("Synced %v users.", len(userNames)) + + // Get repositories + log.Infof("Retrieving repositories from Gitea ...") + repos, err := listAllPages(func(page, perPage int) ([]*gitea.Repository, error) { + repos, _, err := i.c.SearchRepos(gitea.SearchRepoOptions{ + ListOptions: gitea.ListOptions{ + Page: page, + PageSize: perPage, + }, + Sort: "created", + Order: "desc", }) - return orgs, err - }, i.listInterval) + return repos, err + }) if err != nil { - return errors.Wrap(err, "listing organizations") + return errors.Wrap(err, "listing repositories") } - for _, giteaOrg := range giteaOrgs { - giteaRepos, err := listAllPages(func(page, perPage int) ([]*gitea.Repository, error) { - repos, _, err := i.c.ListOrgRepos(giteaOrg.UserName, gitea.ListOrgReposOptions{ - ListOptions: gitea.ListOptions{Page: page, PageSize: perPage}, - }) - return repos, err - }, i.listInterval) - if err != nil { - return errors.Wrap(err, "listing org repositories") - } - giteaOrgMembers, err := listAllPages(func(page, perPage int) ([]*gitea.User, error) { - members, _, err := i.c.ListOrgMembership(giteaOrg.UserName, gitea.ListOrgMembershipOption{ - ListOptions: gitea.ListOptions{Page: page, PageSize: perPage}, - }) - return members, err - }, i.listInterval) - if err != nil { - return errors.Wrap(err, "listing org members") - } - memberIDs := lo.Flatten(ds.Map(giteaOrgMembers, func(member *gitea.User) []string { - user, ok := usersMap[member.UserName] - if ok { - return []string{user.ID} - } else { - log.Warnf("failed to find user %v", member.UserName) - return nil + // Sync repositories + log.Infof("Syncing %v repositories ...", len(repos)) + var eg errgroup.Group + eg.SetLimit(i.concurrency) + for _, repo := range repos { + repo := repo + eg.Go(func() error { + // Get users with write access + members, _, err := i.c.GetAssignees(repo.Owner.UserName, repo.Name) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("syncing repository %v/%v: getting users", repo.Owner.UserName, repo.Name)) } - })) - - for _, giteaRepo := range giteaRepos { - err = i.syncRepository(ctx, giteaOrg.UserName, memberIDs, giteaRepo) - } - - time.Sleep(i.listInterval) + memberIDs := lo.Flatten(ds.Map(members, func(member *gitea.User) []string { + user, ok := usersMap[member.UserName] + if ok { + return []string{user.ID} + } else { + log.Warnf("failed to find user %v", member.UserName) + return nil + } + })) + // Sync repository and apps + return i.syncRepository(ctx, repo.Owner.UserName, memberIDs, repo) + }) } - - return nil + return eg.Wait() } func (i *Integration) syncRepository(ctx context.Context, username string, giteaOwnerIDs []string, giteaRepo *gitea.Repository) error { @@ -149,7 +121,7 @@ func (i *Integration) syncRepository(ctx context.Context, username string, gitea optional.From(domain.RepositoryAuth{Method: domain.RepositoryAuthMethodSSH}), giteaOwnerIDs, ) - log.Infof("Syncing repository %v -> id: %v", repo.Name, repo.ID) + log.Infof("New repository %v (id: %v)", repo.Name, repo.ID) return i.gitRepo.CreateRepository(ctx, repo) }