Merge branch 'main' into add-pipeline-editor

This commit is contained in:
Vardan Bansal 2023-09-08 21:27:59 -07:00
commit 94e4cca4d6
86 changed files with 1863 additions and 562 deletions

View File

@ -13,6 +13,7 @@ import (
"github.com/harness/gitness/events" "github.com/harness/gitness/events"
"github.com/harness/gitness/gitrpc" "github.com/harness/gitness/gitrpc"
"github.com/harness/gitness/gitrpc/server" "github.com/harness/gitness/gitrpc/server"
"github.com/harness/gitness/internal/services/trigger"
"github.com/harness/gitness/internal/services/webhook" "github.com/harness/gitness/internal/services/webhook"
"github.com/harness/gitness/lock" "github.com/harness/gitness/lock"
"github.com/harness/gitness/store/database" "github.com/harness/gitness/store/database"
@ -147,23 +148,26 @@ func ProvideEventsConfig() (events.Config, error) {
return config, nil return config, nil
} }
// ProvideWebhookConfig loads the webhook config from the environment. // ProvideWebhookConfig loads the webhook service config from the main config.
// It backfills certain config elements if required. func ProvideWebhookConfig(config *types.Config) webhook.Config {
func ProvideWebhookConfig() (webhook.Config, error) { return webhook.Config{
config := webhook.Config{} UserAgentIdentity: config.Webhook.UserAgentIdentity,
err := envconfig.Process("", &config) HeaderIdentity: config.Webhook.HeaderIdentity,
if err != nil { EventReaderName: config.InstanceID,
return webhook.Config{}, fmt.Errorf("failed to load events config: %w", err) Concurrency: config.Webhook.Concurrency,
MaxRetries: config.Webhook.MaxRetries,
AllowPrivateNetwork: config.Webhook.AllowPrivateNetwork,
AllowLoopback: config.Webhook.AllowLoopback,
} }
}
if config.EventReaderName == "" { // ProvideTriggerConfig loads the trigger service config from the main config.
config.EventReaderName, err = getSanitizedMachineName() func ProvideTriggerConfig(config *types.Config) trigger.Config {
if err != nil { return trigger.Config{
return webhook.Config{}, fmt.Errorf("failed to get sanitized machine name: %w", err) EventReaderName: config.InstanceID,
} Concurrency: config.Webhook.Concurrency,
MaxRetries: config.Webhook.MaxRetries,
} }
return config, nil
} }
// ProvideLockConfig generates the `lock` package config from the gitness config. // ProvideLockConfig generates the `lock` package config from the gitness config.

View File

@ -32,7 +32,7 @@ import (
"github.com/harness/gitness/internal/api/controller/space" "github.com/harness/gitness/internal/api/controller/space"
"github.com/harness/gitness/internal/api/controller/system" "github.com/harness/gitness/internal/api/controller/system"
"github.com/harness/gitness/internal/api/controller/template" "github.com/harness/gitness/internal/api/controller/template"
"github.com/harness/gitness/internal/api/controller/trigger" controllertrigger "github.com/harness/gitness/internal/api/controller/trigger"
"github.com/harness/gitness/internal/api/controller/user" "github.com/harness/gitness/internal/api/controller/user"
controllerwebhook "github.com/harness/gitness/internal/api/controller/webhook" controllerwebhook "github.com/harness/gitness/internal/api/controller/webhook"
"github.com/harness/gitness/internal/auth/authn" "github.com/harness/gitness/internal/auth/authn"
@ -41,6 +41,7 @@ import (
gitevents "github.com/harness/gitness/internal/events/git" gitevents "github.com/harness/gitness/internal/events/git"
pullreqevents "github.com/harness/gitness/internal/events/pullreq" pullreqevents "github.com/harness/gitness/internal/events/pullreq"
"github.com/harness/gitness/internal/pipeline/commit" "github.com/harness/gitness/internal/pipeline/commit"
eventsstream "github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/pipeline/file" "github.com/harness/gitness/internal/pipeline/file"
"github.com/harness/gitness/internal/pipeline/manager" "github.com/harness/gitness/internal/pipeline/manager"
"github.com/harness/gitness/internal/pipeline/runner" "github.com/harness/gitness/internal/pipeline/runner"
@ -50,8 +51,10 @@ import (
"github.com/harness/gitness/internal/server" "github.com/harness/gitness/internal/server"
"github.com/harness/gitness/internal/services" "github.com/harness/gitness/internal/services"
"github.com/harness/gitness/internal/services/codecomments" "github.com/harness/gitness/internal/services/codecomments"
"github.com/harness/gitness/internal/services/importer"
"github.com/harness/gitness/internal/services/job" "github.com/harness/gitness/internal/services/job"
pullreqservice "github.com/harness/gitness/internal/services/pullreq" pullreqservice "github.com/harness/gitness/internal/services/pullreq"
"github.com/harness/gitness/internal/services/trigger"
"github.com/harness/gitness/internal/services/webhook" "github.com/harness/gitness/internal/services/webhook"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/cache" "github.com/harness/gitness/internal/store/cache"
@ -104,6 +107,8 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
events.WireSet, events.WireSet,
cliserver.ProvideWebhookConfig, cliserver.ProvideWebhookConfig,
webhook.WireSet, webhook.WireSet,
cliserver.ProvideTriggerConfig,
trigger.WireSet,
githook.WireSet, githook.WireSet,
cliserver.ProvideLockConfig, cliserver.ProvideLockConfig,
lock.WireSet, lock.WireSet,
@ -124,10 +129,12 @@ func initSystem(ctx context.Context, config *types.Config) (*cliserver.System, e
triggerer.WireSet, triggerer.WireSet,
file.WireSet, file.WireSet,
runner.WireSet, runner.WireSet,
eventsstream.WireSet,
scheduler.WireSet, scheduler.WireSet,
commit.WireSet, commit.WireSet,
trigger.WireSet, controllertrigger.WireSet,
plugin.WireSet, plugin.WireSet,
importer.WireSet,
) )
return &cliserver.System{}, nil return &cliserver.System{}, nil
} }

View File

@ -8,10 +8,9 @@ package main
import ( import (
"context" "context"
"github.com/harness/gitness/cli/server" "github.com/harness/gitness/cli/server"
"github.com/harness/gitness/encrypt" "github.com/harness/gitness/encrypt"
"github.com/harness/gitness/events" events2 "github.com/harness/gitness/events"
"github.com/harness/gitness/gitrpc" "github.com/harness/gitness/gitrpc"
server3 "github.com/harness/gitness/gitrpc/server" server3 "github.com/harness/gitness/gitrpc/server"
"github.com/harness/gitness/gitrpc/server/cron" "github.com/harness/gitness/gitrpc/server/cron"
@ -37,9 +36,10 @@ import (
"github.com/harness/gitness/internal/auth/authn" "github.com/harness/gitness/internal/auth/authn"
"github.com/harness/gitness/internal/auth/authz" "github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/bootstrap" "github.com/harness/gitness/internal/bootstrap"
events3 "github.com/harness/gitness/internal/events/git" events4 "github.com/harness/gitness/internal/events/git"
events2 "github.com/harness/gitness/internal/events/pullreq" events3 "github.com/harness/gitness/internal/events/pullreq"
"github.com/harness/gitness/internal/pipeline/commit" "github.com/harness/gitness/internal/pipeline/commit"
"github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/pipeline/file" "github.com/harness/gitness/internal/pipeline/file"
"github.com/harness/gitness/internal/pipeline/manager" "github.com/harness/gitness/internal/pipeline/manager"
"github.com/harness/gitness/internal/pipeline/runner" "github.com/harness/gitness/internal/pipeline/runner"
@ -49,8 +49,10 @@ import (
server2 "github.com/harness/gitness/internal/server" server2 "github.com/harness/gitness/internal/server"
"github.com/harness/gitness/internal/services" "github.com/harness/gitness/internal/services"
"github.com/harness/gitness/internal/services/codecomments" "github.com/harness/gitness/internal/services/codecomments"
"github.com/harness/gitness/internal/services/importer"
"github.com/harness/gitness/internal/services/job" "github.com/harness/gitness/internal/services/job"
pullreq2 "github.com/harness/gitness/internal/services/pullreq" pullreq2 "github.com/harness/gitness/internal/services/pullreq"
trigger2 "github.com/harness/gitness/internal/services/trigger"
"github.com/harness/gitness/internal/services/webhook" "github.com/harness/gitness/internal/services/webhook"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/store/cache" "github.com/harness/gitness/internal/store/cache"
@ -104,17 +106,29 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
if err != nil { if err != nil {
return nil, err return nil, err
} }
repoController := repo.ProvideController(config, db, provider, pathUID, authorizer, pathStore, repoStore, spaceStore, pipelineStore, principalStore, gitrpcInterface) jobStore := database.ProvideJobStore(db)
executionStore := database.ProvideExecutionStore(db) pubsubConfig := pubsub.ProvideConfig(config)
commitService := commit.ProvideCommitService(gitrpcInterface)
stageStore := database.ProvideStageStore(db)
fileService := file.ProvideFileService(gitrpcInterface)
lockConfig := server.ProvideLockConfig(config)
universalClient, err := server.ProvideRedis(config) universalClient, err := server.ProvideRedis(config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
pubSub := pubsub.ProvidePubSub(pubsubConfig, universalClient)
executor := job.ProvideExecutor(jobStore, pubSub)
lockConfig := server.ProvideLockConfig(config)
mutexManager := lock.ProvideMutexManager(lockConfig, universalClient) mutexManager := lock.ProvideMutexManager(lockConfig, universalClient)
jobScheduler, err := job.ProvideScheduler(jobStore, executor, mutexManager, pubSub, config)
if err != nil {
return nil, err
}
repository, err := importer.ProvideRepoImporter(provider, gitrpcInterface, repoStore, jobScheduler, executor)
if err != nil {
return nil, err
}
repoController := repo.ProvideController(config, db, provider, pathUID, authorizer, pathStore, repoStore, spaceStore, pipelineStore, principalStore, gitrpcInterface, repository)
executionStore := database.ProvideExecutionStore(db)
commitService := commit.ProvideCommitService(gitrpcInterface)
stageStore := database.ProvideStageStore(db)
fileService := file.ProvideFileService(gitrpcInterface)
schedulerScheduler, err := scheduler.ProvideScheduler(stageStore, mutexManager) schedulerScheduler, err := scheduler.ProvideScheduler(stageStore, mutexManager)
if err != nil { if err != nil {
return nil, err return nil, err
@ -125,10 +139,11 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
logStore := logs.ProvideLogStore(db, config) logStore := logs.ProvideLogStore(db, config)
logStream := livelog.ProvideLogStream(config) logStream := livelog.ProvideLogStream(config)
logsController := logs2.ProvideController(db, authorizer, executionStore, repoStore, pipelineStore, stageStore, stepStore, logStore, logStream) logsController := logs2.ProvideController(db, authorizer, executionStore, repoStore, pipelineStore, stageStore, stepStore, logStore, logStream)
eventsStreamer := events.ProvideEventsStreaming(pubSub)
secretStore := database.ProvideSecretStore(db) secretStore := database.ProvideSecretStore(db)
connectorStore := database.ProvideConnectorStore(db) connectorStore := database.ProvideConnectorStore(db)
templateStore := database.ProvideTemplateStore(db) templateStore := database.ProvideTemplateStore(db)
spaceController := space.ProvideController(db, provider, pathUID, authorizer, pathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore) spaceController := space.ProvideController(db, provider, eventsStreamer, pathUID, authorizer, pathStore, pipelineStore, secretStore, connectorStore, templateStore, spaceStore, repoStore, principalStore, repoController, membershipStore)
pipelineController := pipeline.ProvideController(db, pathUID, pathStore, repoStore, authorizer, pipelineStore) pipelineController := pipeline.ProvideController(db, pathUID, pathStore, repoStore, authorizer, pipelineStore)
encrypter, err := encrypt.ProvideEncrypter(config) encrypter, err := encrypt.ProvideEncrypter(config)
if err != nil { if err != nil {
@ -150,27 +165,24 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
if err != nil { if err != nil {
return nil, err return nil, err
} }
eventsSystem, err := events.ProvideSystem(eventsConfig, universalClient) eventsSystem, err := events2.ProvideSystem(eventsConfig, universalClient)
if err != nil { if err != nil {
return nil, err return nil, err
} }
reporter, err := events2.ProvideReporter(eventsSystem) reporter, err := events3.ProvideReporter(eventsSystem)
if err != nil { if err != nil {
return nil, err return nil, err
} }
migrator := codecomments.ProvideMigrator(gitrpcInterface) migrator := codecomments.ProvideMigrator(gitrpcInterface)
pullreqController := pullreq.ProvideController(db, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, gitrpcInterface, reporter, mutexManager, migrator) pullreqController := pullreq.ProvideController(db, provider, authorizer, pullReqStore, pullReqActivityStore, codeCommentView, pullReqReviewStore, pullReqReviewerStore, repoStore, principalStore, gitrpcInterface, reporter, mutexManager, migrator)
webhookConfig, err := server.ProvideWebhookConfig() webhookConfig := server.ProvideWebhookConfig(config)
if err != nil {
return nil, err
}
webhookStore := database.ProvideWebhookStore(db) webhookStore := database.ProvideWebhookStore(db)
webhookExecutionStore := database.ProvideWebhookExecutionStore(db) webhookExecutionStore := database.ProvideWebhookExecutionStore(db)
readerFactory, err := events3.ProvideReaderFactory(eventsSystem) readerFactory, err := events4.ProvideReaderFactory(eventsSystem)
if err != nil { if err != nil {
return nil, err return nil, err
} }
eventsReaderFactory, err := events2.ProvideReaderFactory(eventsSystem) eventsReaderFactory, err := events3.ProvideReaderFactory(eventsSystem)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -179,7 +191,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
return nil, err return nil, err
} }
webhookController := webhook2.ProvideController(webhookConfig, db, authorizer, webhookStore, webhookExecutionStore, repoStore, webhookService) webhookController := webhook2.ProvideController(webhookConfig, db, authorizer, webhookStore, webhookExecutionStore, repoStore, webhookService)
eventsReporter, err := events3.ProvideReporter(eventsSystem) eventsReporter, err := events4.ProvideReporter(eventsSystem)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -194,7 +206,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
webHandler := router.ProvideWebHandler(config) webHandler := router.ProvideWebHandler(config)
routerRouter := router.ProvideRouter(config, apiHandler, gitHandler, webHandler) routerRouter := router.ProvideRouter(config, apiHandler, gitHandler, webHandler)
serverServer := server2.ProvideServer(config, routerRouter) serverServer := server2.ProvideServer(config, routerRouter)
executionManager := manager.ProvideExecutionManager(config, executionStore, pipelineStore, provider, fileService, logStore, logStream, repoStore, schedulerScheduler, secretStore, stageStore, stepStore, principalStore) executionManager := manager.ProvideExecutionManager(config, executionStore, pipelineStore, provider, eventsStreamer, fileService, logStore, logStream, repoStore, schedulerScheduler, secretStore, stageStore, stepStore, principalStore)
client := manager.ProvideExecutionClient(executionManager, config) client := manager.ProvideExecutionClient(executionManager, config)
runtimeRunner, err := runner.ProvideExecutionRunner(config, client, executionManager) runtimeRunner, err := runner.ProvideExecutionRunner(config, client, executionManager)
if err != nil { if err != nil {
@ -218,19 +230,16 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
cronManager := cron.ProvideManager(serverConfig) cronManager := cron.ProvideManager(serverConfig)
repoGitInfoView := database.ProvideRepoGitInfoView(db) repoGitInfoView := database.ProvideRepoGitInfoView(db)
repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView) repoGitInfoCache := cache.ProvideRepoGitInfoCache(repoGitInfoView)
pubsubConfig := pubsub.ProvideConfig(config)
pubSub := pubsub.ProvidePubSub(pubsubConfig, universalClient)
pullreqService, err := pullreq2.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter, gitrpcInterface, db, repoGitInfoCache, repoStore, pullReqStore, pullReqActivityStore, codeCommentView, migrator, pubSub, provider) pullreqService, err := pullreq2.ProvideService(ctx, config, readerFactory, eventsReaderFactory, reporter, gitrpcInterface, db, repoGitInfoCache, repoStore, pullReqStore, pullReqActivityStore, codeCommentView, migrator, pubSub, provider)
if err != nil { if err != nil {
return nil, err return nil, err
} }
jobStore := database.ProvideJobStore(db) triggerConfig := server.ProvideTriggerConfig(config)
executor := job.ProvideExecutor(jobStore, pubSub) triggerService, err := trigger2.ProvideService(ctx, triggerConfig, readerFactory, eventsReaderFactory)
jobScheduler, err := job.ProvideScheduler(jobStore, executor, mutexManager, pubSub, config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
servicesServices := services.ProvideServices(webhookService, pullreqService, executor, jobScheduler) servicesServices := services.ProvideServices(webhookService, pullreqService, triggerService, jobScheduler)
serverSystem := server.NewSystem(bootstrapBootstrap, serverServer, poller, grpcServer, cronManager, servicesServices) serverSystem := server.NewSystem(bootstrapBootstrap, serverServer, poller, grpcServer, cronManager, servicesServices)
return serverSystem, nil return serverSystem, nil
} }

View File

@ -43,9 +43,9 @@ func (f *ReaderFactory[R]) Launch(ctx context.Context,
// setup ctx with copied logger that has extra fields set // setup ctx with copied logger that has extra fields set
log := log.Ctx(ctx).With(). log := log.Ctx(ctx).With().
Str("events_category", f.category). Str("events.category", f.category).
Str("events_group_name", groupName). Str("events.group_name", groupName).
Str("events_reader_name", readerName). Str("events.reader_name", readerName).
Logger() Logger()
// create new stream consumer using factory method // create new stream consumer using factory method
@ -191,8 +191,8 @@ func ReaderRegisterEvent[T interface{}](reader *GenericReader,
// update ctx with event type for proper logging // update ctx with event type for proper logging
log := log.Ctx(ctx).With(). log := log.Ctx(ctx).With().
Str("events_type", string(eventType)). Str("events.type", string(eventType)).
Str("events_id", event.ID). Str("events.id", event.ID).
Logger() Logger()
ctx = log.WithContext(ctx) ctx = log.WithContext(ctx)

View File

@ -30,6 +30,8 @@ type Interface interface {
// not update of an exiting one, set the zero ref as the OldValue. // not update of an exiting one, set the zero ref as the OldValue.
UpdateRef(ctx context.Context, params UpdateRefParams) error UpdateRef(ctx context.Context, params UpdateRefParams) error
SyncRepository(ctx context.Context, params *SyncRepositoryParams) (*SyncRepositoryOutput, error)
/* /*
* Commits service * Commits service
*/ */

View File

@ -354,7 +354,9 @@ func (s RepositoryService) SyncRepository(
return nil, processGitErrorf(err, "failed to set default branch of repo") return nil, processGitErrorf(err, "failed to set default branch of repo")
} }
return &rpc.SyncRepositoryResponse{}, nil return &rpc.SyncRepositoryResponse{
DefaultBranch: defaultBranch,
}, nil
} }
func (s RepositoryService) HashRepository( func (s RepositoryService) HashRepository(

View File

@ -203,7 +203,9 @@ message SyncRepositoryRequest {
} }
message SyncRepositoryResponse { message SyncRepositoryResponse {
string default_branch = 1;
} }
enum HashType { enum HashType {
HashTypeSHA256 = 0; HashTypeSHA256 = 0;
} }

View File

@ -63,6 +63,7 @@ type SyncRepositoryParams struct {
} }
type SyncRepositoryOutput struct { type SyncRepositoryOutput struct {
DefaultBranch string
} }
type HashRepositoryParams struct { type HashRepositoryParams struct {
@ -164,7 +165,7 @@ func (c *Client) DeleteRepository(ctx context.Context, params *DeleteRepositoryP
} }
func (c *Client) SyncRepository(ctx context.Context, params *SyncRepositoryParams) (*SyncRepositoryOutput, error) { func (c *Client) SyncRepository(ctx context.Context, params *SyncRepositoryParams) (*SyncRepositoryOutput, error) {
_, err := c.repoService.SyncRepository(ctx, &rpc.SyncRepositoryRequest{ result, err := c.repoService.SyncRepository(ctx, &rpc.SyncRepositoryRequest{
Base: mapToRPCWriteRequest(params.WriteParams), Base: mapToRPCWriteRequest(params.WriteParams),
Source: params.Source, Source: params.Source,
CreateIfNotExists: params.CreateIfNotExists, CreateIfNotExists: params.CreateIfNotExists,
@ -173,7 +174,9 @@ func (c *Client) SyncRepository(ctx context.Context, params *SyncRepositoryParam
return nil, processRPCErrorf(err, "failed to sync repository on server to match provided source") return nil, processRPCErrorf(err, "failed to sync repository on server to match provided source")
} }
return &SyncRepositoryOutput{}, nil return &SyncRepositoryOutput{
DefaultBranch: result.DefaultBranch,
}, nil
} }
func (c *Client) HashRepository(ctx context.Context, params *HashRepositoryParams) (*HashRepositoryOutput, error) { func (c *Client) HashRepository(ctx context.Context, params *HashRepositoryParams) (*HashRepositoryOutput, error) {

View File

@ -1987,6 +1987,8 @@ type SyncRepositoryResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
DefaultBranch string `protobuf:"bytes,1,opt,name=default_branch,json=defaultBranch,proto3" json:"default_branch,omitempty"`
} }
func (x *SyncRepositoryResponse) Reset() { func (x *SyncRepositoryResponse) Reset() {
@ -2021,6 +2023,13 @@ func (*SyncRepositoryResponse) Descriptor() ([]byte, []int) {
return file_repo_proto_rawDescGZIP(), []int{29} return file_repo_proto_rawDescGZIP(), []int{29}
} }
func (x *SyncRepositoryResponse) GetDefaultBranch() string {
if x != nil {
return x.DefaultBranch
}
return ""
}
type HashRepositoryRequest struct { type HashRepositoryRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -2438,114 +2447,117 @@ var file_repo_proto_rawDesc = []byte{
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2f, 0x0a, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2f, 0x0a,
0x14, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x66, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x65, 0x14, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x66, 0x5f, 0x6e, 0x6f, 0x74, 0x5f, 0x65,
0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x63, 0x72, 0x65, 0x78, 0x69, 0x73, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x63, 0x72, 0x65,
0x61, 0x74, 0x65, 0x49, 0x66, 0x4e, 0x6f, 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x18, 0x61, 0x74, 0x65, 0x49, 0x66, 0x4e, 0x6f, 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x3f,
0x0a, 0x16, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x0a, 0x16, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xae, 0x01, 0x0a, 0x15, 0x48, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61,
0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x75, 0x6c, 0x74, 0x5f, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x22,
0xae, 0x01, 0x0a, 0x15, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f,
0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x62, 0x61, 0x73,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65,
0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12,
0x2a, 0x0a, 0x09, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70,
0x65, 0x52, 0x08, 0x68, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x43, 0x0a, 0x10, 0x61,
0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x61, 0x73, 0x68,
0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52,
0x0f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65,
0x22, 0x2c, 0x0a, 0x16, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f,
0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61,
0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x60,
0x0a, 0x10, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x62, 0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x32, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x09, 0x68, 0x61, 0x73, 0x68, 0x73, 0x74, 0x52, 0x04, 0x62, 0x61, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x66, 0x31,
0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x72, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x66, 0x31, 0x12, 0x12, 0x0a, 0x04,
0x63, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x68, 0x61, 0x73, 0x68, 0x72, 0x65, 0x66, 0x32, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x66, 0x32,
0x54, 0x79, 0x70, 0x65, 0x12, 0x43, 0x0a, 0x10, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x22, 0x39, 0x0a, 0x11, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73,
0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x18, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x62,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d,
0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0f, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61, 0x2a, 0x52, 0x0a, 0x0c, 0x54,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x22, 0x2c, 0x0a, 0x16, 0x48, 0x61, 0x73, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54,
0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x54, 0x72, 0x65, 0x65, 0x10,
0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70,
0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x60, 0x0a, 0x10, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x72, 0x65, 0x65, 0x4e,
0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x10, 0x02, 0x2a,
0x61, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x81, 0x01, 0x0a, 0x0c, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65,
0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x04, 0x62, 0x61, 0x73, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65,
0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x66, 0x31, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f,
0x04, 0x72, 0x65, 0x66, 0x31, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x66, 0x32, 0x18, 0x03, 0x20, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x53, 0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x10, 0x01, 0x12,
0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x66, 0x32, 0x22, 0x39, 0x0a, 0x11, 0x4d, 0x65, 0x72, 0x14, 0x0a, 0x10, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x45,
0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x78, 0x65, 0x63, 0x10, 0x02, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64,
0x0a, 0x0e, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x54, 0x72, 0x65, 0x65, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x54,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69,
0x65, 0x53, 0x68, 0x61, 0x2a, 0x52, 0x0a, 0x0c, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x74, 0x10, 0x04, 0x2a, 0x1e, 0x0a, 0x08, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12,
0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0e, 0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x53, 0x48, 0x41, 0x32, 0x35,
0x54, 0x79, 0x70, 0x65, 0x54, 0x72, 0x65, 0x65, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x72, 0x36, 0x10, 0x00, 0x2a, 0x31, 0x0a, 0x13, 0x48, 0x61, 0x73, 0x68, 0x41, 0x67, 0x67, 0x72, 0x65,
0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x10, 0x01, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x48, 0x61,
0x12, 0x16, 0x0a, 0x12, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x54, 0x79, 0x70, 0x65, 0x73, 0x68, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70,
0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x10, 0x02, 0x2a, 0x81, 0x01, 0x0a, 0x0c, 0x54, 0x72, 0x65, 0x65, 0x58, 0x4f, 0x52, 0x10, 0x00, 0x32, 0xb8, 0x07, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x73,
0x65, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x72, 0x65, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x10,
0x65, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x10, 0x00, 0x12,
0x17, 0x0a, 0x13, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x53,
0x79, 0x6d, 0x6c, 0x69, 0x6e, 0x6b, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x72, 0x65, 0x65,
0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x45, 0x78, 0x65, 0x63, 0x10, 0x02, 0x12, 0x14,
0x0a, 0x10, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x54, 0x72,
0x65, 0x65, 0x10, 0x03, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65,
0x4d, 0x6f, 0x64, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x10, 0x04, 0x2a, 0x1e, 0x0a, 0x08,
0x48, 0x61, 0x73, 0x68, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x48, 0x61, 0x73, 0x68,
0x54, 0x79, 0x70, 0x65, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x10, 0x00, 0x2a, 0x31, 0x0a, 0x13,
0x48, 0x61, 0x73, 0x68, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54,
0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x48, 0x61, 0x73, 0x68, 0x41, 0x67, 0x67, 0x72, 0x65,
0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x58, 0x4f, 0x52, 0x10, 0x00, 0x32,
0xb8, 0x07, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52,
0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1c, 0x2e, 0x72, 0x70, 0x63, 0x2e,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, 0x12, 0x1c, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70,
0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x40, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73,
0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x17, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12,
0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x40, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x17,
0x1a, 0x18, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65,
0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x48, 0x0a, 0x0d, 0x4c, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65,
0x73, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x72, 0x70, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x12, 0x48, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x65, 0x73, 0x12, 0x19, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x65,
0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e,
0x73, 0x65, 0x30, 0x01, 0x12, 0x43, 0x0a, 0x0c, 0x50, 0x61, 0x74, 0x68, 0x73, 0x44, 0x65, 0x74, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x72, 0x65, 0x65, 0x4e, 0x6f, 0x64, 0x65,
0x61, 0x69, 0x6c, 0x73, 0x12, 0x18, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x43, 0x0a, 0x0c, 0x50,
0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x61, 0x74, 0x68, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x18, 0x2e, 0x72, 0x70,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x63, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x50, 0x61, 0x74, 0x68,
0x53, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x18, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x12, 0x43, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x12, 0x18, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6d, 0x6f, 0x64,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x72, 0x70, 0x63,
0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x52, 0x65, 0x73,
0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x12, 0x13, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x6c, 0x6f, 0x62, 0x52, 0x65,
0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x42, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x42,
0x6d, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x17, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x6c, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x42, 0x0a,
0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x12, 0x17, 0x2e, 0x72,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x65,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x09, 0x47, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x15, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30,
0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x01, 0x12, 0x3a, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x12, 0x15,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43,
0x6d, 0x69, 0x74, 0x44, 0x69, 0x76, 0x65, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x20, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5b, 0x0a,
0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x44, 0x69, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x44, 0x69, 0x76, 0x65, 0x72, 0x67,
0x76, 0x65, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x20, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43,
0x1a, 0x21, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x44, 0x69, 0x76, 0x65, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x73,
0x44, 0x69, 0x76, 0x65, 0x72, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x47, 0x65,
0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x44, 0x69, 0x76, 0x65, 0x72, 0x67, 0x65, 0x6e, 0x63,
0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1c, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, 0x10, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1c,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73,
0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x72,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6f, 0x70, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x79, 0x6e, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0e, 0x53,
0x63, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x2e,
0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f,
0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x72, 0x70, 0x63, 0x2e,
0x00, 0x12, 0x4b, 0x0a, 0x0e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x53, 0x79, 0x6e, 0x63, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65,
0x6f, 0x72, 0x79, 0x12, 0x1a, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x0e, 0x48, 0x61, 0x73, 0x68,
0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x2e, 0x72, 0x70, 0x63,
0x1b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x2e, 0x48, 0x61, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52,
0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x48, 0x61, 0x73,
0x0a, 0x09, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x12, 0x15, 0x2e, 0x72, 0x70, 0x68, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x63, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x09, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61,
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x12, 0x15, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61,
0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x70, 0x63, 0x2e,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x72, 0x6e, 0x65, 0x73, 0x73, 0x4d, 0x65, 0x72, 0x67, 0x65, 0x42, 0x61, 0x73, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x2f, 0x67, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x65, 0x42, 0x27, 0x5a, 0x25, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x68, 0x61, 0x72, 0x6e, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2f,
0x67, 0x69, 0x74, 0x72, 0x70, 0x63, 0x2f, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
} }
var ( var (

2
go.mod
View File

@ -25,7 +25,6 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/google/go-cmp v0.5.9 github.com/google/go-cmp v0.5.9
github.com/google/uuid v1.3.1
github.com/google/wire v0.5.0 github.com/google/wire v0.5.0
github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75
github.com/gotidy/ptr v1.3.0 github.com/gotidy/ptr v1.3.0
@ -81,6 +80,7 @@ require (
github.com/ghodss/yaml v1.0.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
github.com/googleapis/gax-go/v2 v2.7.0 // indirect github.com/googleapis/gax-go/v2 v2.7.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect

1
go.sum
View File

@ -317,6 +317,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/guregu/null v4.0.0+incompatible h1:4zw0ckM7ECd6FNNddc3Fu4aty9nTlpkkzH7dPn4/4Gw= github.com/guregu/null v4.0.0+incompatible h1:4zw0ckM7ECd6FNNddc3Fu4aty9nTlpkkzH7dPn4/4Gw=
github.com/guregu/null v4.0.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM= github.com/guregu/null v4.0.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM=
github.com/h2non/gock v1.0.9 h1:17gCehSo8ZOgEsFKpQgqHiR7VLyjxdAG3lkhVvO9QZU=
github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE=
github.com/harness/go-rbac v0.0.0-20230829014129-c9b217856ea2 h1:M1Jd2uEKl4YW9g/6vzN1qo06d5dshYYdwxlhOTUSnh4= github.com/harness/go-rbac v0.0.0-20230829014129-c9b217856ea2 h1:M1Jd2uEKl4YW9g/6vzN1qo06d5dshYYdwxlhOTUSnh4=
github.com/harness/go-rbac v0.0.0-20230829014129-c9b217856ea2/go.mod h1:uGgBgSZPgyygG5rWzoYsKIQ8TM4zt5yQq9nreznWvOI= github.com/harness/go-rbac v0.0.0-20230829014129-c9b217856ea2/go.mod h1:uGgBgSZPgyygG5rWzoYsKIQ8TM4zt5yQq9nreznWvOI=

View File

@ -114,6 +114,10 @@ func (c *Controller) getRepoCheckAccess(ctx context.Context,
return nil, fmt.Errorf("failed to find repository: %w", err) return nil, fmt.Errorf("failed to find repository: %w", err)
} }
if repo.Importing {
return nil, usererror.BadRequest("Repository import is in progress.")
}
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission, false); err != nil { if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, reqPermission, false); err != nil {
return nil, fmt.Errorf("access check failed: %w", err) return nil, fmt.Errorf("access check failed: %w", err)
} }

View File

@ -7,11 +7,14 @@ package repo
import ( import (
"context" "context"
"fmt" "fmt"
"strconv"
"strings"
"github.com/harness/gitness/gitrpc" "github.com/harness/gitness/gitrpc"
"github.com/harness/gitness/internal/auth" "github.com/harness/gitness/internal/auth"
"github.com/harness/gitness/internal/auth/authz" "github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/githook" "github.com/harness/gitness/internal/githook"
"github.com/harness/gitness/internal/services/importer"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/url" "github.com/harness/gitness/internal/url"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
@ -32,6 +35,7 @@ type Controller struct {
pipelineStore store.PipelineStore pipelineStore store.PipelineStore
principalStore store.PrincipalStore principalStore store.PrincipalStore
gitRPCClient gitrpc.Interface gitRPCClient gitrpc.Interface
importer *importer.Repository
} }
func NewController( func NewController(
@ -46,6 +50,7 @@ func NewController(
pipelineStore store.PipelineStore, pipelineStore store.PipelineStore,
principalStore store.PrincipalStore, principalStore store.PrincipalStore,
gitRPCClient gitrpc.Interface, gitRPCClient gitrpc.Interface,
importer *importer.Repository,
) *Controller { ) *Controller {
return &Controller{ return &Controller{
defaultBranch: defaultBranch, defaultBranch: defaultBranch,
@ -59,6 +64,7 @@ func NewController(
pipelineStore: pipelineStore, pipelineStore: pipelineStore,
principalStore: principalStore, principalStore: principalStore,
gitRPCClient: gitRPCClient, gitRPCClient: gitRPCClient,
importer: importer,
} }
} }
@ -95,3 +101,12 @@ func CreateRPCReadParams(repo *types.Repository) gitrpc.ReadParams {
RepoUID: repo.GitUID, RepoUID: repo.GitUID,
} }
} }
func (c *Controller) validateParentRef(parentRef string) error {
parentRefAsID, err := strconv.ParseInt(parentRef, 10, 64)
if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(parentRef)) == 0) {
return errRepositoryRequiresParent
}
return nil
}

View File

@ -8,7 +8,6 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"strconv"
"strings" "strings"
"time" "time"
@ -151,10 +150,8 @@ func (c *Controller) getSpaceCheckAuthRepoCreation(
} }
func (c *Controller) sanitizeCreateInput(in *CreateInput) error { func (c *Controller) sanitizeCreateInput(in *CreateInput) error {
parentRefAsID, err := strconv.ParseInt(in.ParentRef, 10, 64) if err := c.validateParentRef(in.ParentRef); err != nil {
return err
if (err == nil && parentRefAsID <= 0) || (len(strings.TrimSpace(in.ParentRef)) == 0) {
return errRepositoryRequiresParent
} }
if err := c.uidCheck(in.UID, false); err != nil { if err := c.uidCheck(in.UID, false); err != nil {

View File

@ -0,0 +1,202 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package repo
import (
"context"
"fmt"
"time"
"github.com/harness/gitness/gitrpc"
"github.com/harness/gitness/internal/api/usererror"
"github.com/harness/gitness/internal/auth"
"github.com/harness/gitness/internal/bootstrap"
"github.com/harness/gitness/internal/githook"
"github.com/harness/gitness/internal/paths"
"github.com/harness/gitness/internal/services/importer"
"github.com/harness/gitness/internal/services/job"
"github.com/harness/gitness/store/database/dbtx"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
type ImportInput struct {
ParentRef string `json:"parent_ref"`
UID string `json:"uid"`
Provider importer.ProviderType `json:"provider"`
ProviderURL string `json:"provider_url"`
RepoSlug string `json:"repo_slug"`
Username string `json:"username"`
Password string `json:"password"`
Description string `json:"description"`
}
// Import creates a new empty repository and starts git import to it from a remote repository.
func (c *Controller) Import(ctx context.Context, session *auth.Session, in *ImportInput) (*types.Repository, error) {
parentSpace, err := c.getSpaceCheckAuthRepoCreation(ctx, session, in.ParentRef)
if err != nil {
return nil, err
}
err = c.sanitizeImportInput(in)
if err != nil {
return nil, fmt.Errorf("failed to sanitize input: %w", err)
}
providerInfo := importer.ProviderInfo{
Type: in.Provider,
Host: in.ProviderURL,
User: in.Username,
Pass: in.Password,
}
repoInfo, err := importer.Repo(ctx, providerInfo, in.RepoSlug)
if err != nil {
return nil, err
}
jobUID, err := job.UID()
if err != nil {
return nil, fmt.Errorf("error creating job UID: %w", err)
}
gitRPCResp, err := c.createEmptyGitRepository(ctx, session)
if err != nil {
return nil, fmt.Errorf("error creating repository on GitRPC: %w", err)
}
now := time.Now().UnixMilli()
repo := &types.Repository{
Version: 0,
ParentID: parentSpace.ID,
UID: in.UID,
GitUID: gitRPCResp.UID,
Path: "", // the path is set in the DB transaction below
Description: in.Description,
IsPublic: repoInfo.IsPublic,
CreatedBy: session.Principal.ID,
Created: now,
Updated: now,
ForkID: 0,
DefaultBranch: repoInfo.DefaultBranch,
Importing: true,
ImportingJobUID: &jobUID,
}
err = dbtx.New(c.db).WithTx(ctx, func(ctx context.Context) error {
// lock parent space path to ensure it doesn't get updated while we setup new repo
spacePath, err := c.pathStore.FindPrimaryWithLock(ctx, enum.PathTargetTypeSpace, parentSpace.ID)
if err != nil {
return usererror.BadRequest("Parent not found'")
}
repo.Path = paths.Concatinate(spacePath.Value, in.UID)
err = c.repoStore.Create(ctx, repo)
if err != nil {
return fmt.Errorf("failed to create repository in storage: %w", err)
}
path := &types.Path{
Version: 0,
Value: repo.Path,
IsPrimary: true,
TargetType: enum.PathTargetTypeRepo,
TargetID: repo.ID,
CreatedBy: repo.CreatedBy,
Created: repo.Created,
Updated: repo.Updated,
}
err = c.pathStore.Create(ctx, path)
if err != nil {
return fmt.Errorf("failed to create path: %w", err)
}
return nil
})
if err != nil {
if err := c.DeleteRepositoryRPC(ctx, session, repo); err != nil {
log.Ctx(ctx).Warn().Err(err).Msg("gitrpc failed to delete repo for cleanup")
}
return nil, err
}
err = c.importer.Run(ctx, jobUID, importer.Input{
RepoID: repo.ID,
GitUser: in.Username,
GitPass: in.Password,
CloneURL: repoInfo.CloneURL,
})
if err != nil {
log.Ctx(ctx).Err(err).Msg("failed to start import repository job")
}
repo.GitURL = c.urlProvider.GenerateRepoCloneURL(repo.Path)
return repo, nil
}
func (c *Controller) sanitizeImportInput(in *ImportInput) error {
if err := c.validateParentRef(in.ParentRef); err != nil {
return err
}
if err := c.uidCheck(in.UID, false); err != nil {
return err
}
if in.Provider == "" {
return usererror.BadRequest("provider must be provided")
}
if in.RepoSlug == "" {
return usererror.BadRequest("repo slug must be provided")
}
return nil
}
func (c *Controller) createEmptyGitRepository(
ctx context.Context,
session *auth.Session,
) (*gitrpc.CreateRepositoryOutput, error) {
// generate envars (add everything githook CLI needs for execution)
envVars, err := githook.GenerateEnvironmentVariables(
ctx,
c.urlProvider.GetAPIBaseURLInternal(),
0,
session.Principal.ID,
true,
)
if err != nil {
return nil, fmt.Errorf("failed to generate git hook environment variables: %w", err)
}
actor := rpcIdentityFromPrincipal(session.Principal)
committer := rpcIdentityFromPrincipal(bootstrap.NewSystemServiceSession().Principal)
now := time.Now()
resp, err := c.gitRPCClient.CreateRepository(ctx, &gitrpc.CreateRepositoryParams{
Actor: *actor,
EnvVars: envVars,
DefaultBranch: c.defaultBranch,
Files: nil,
Author: actor,
AuthorDate: &now,
Committer: committer,
CommitterDate: &now,
})
if err != nil {
return nil, fmt.Errorf("failed to create repo on gitrpc: %w", err)
}
return resp, nil
}

View File

@ -0,0 +1,31 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package repo
import (
"context"
apiauth "github.com/harness/gitness/internal/api/auth"
"github.com/harness/gitness/internal/auth"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
)
// ImportProgress returns progress of the import job.
func (c *Controller) ImportProgress(ctx context.Context,
session *auth.Session,
repoRef string,
) (types.JobProgress, error) {
repo, err := c.repoStore.FindByRef(ctx, repoRef)
if err != nil {
return types.JobProgress{}, err
}
if err = apiauth.CheckRepo(ctx, c.authorizer, session, repo, enum.PermissionRepoView, false); err != nil {
return types.JobProgress{}, err
}
return c.importer.GetProgress(ctx, repo)
}

View File

@ -7,6 +7,7 @@ package repo
import ( import (
"github.com/harness/gitness/gitrpc" "github.com/harness/gitness/gitrpc"
"github.com/harness/gitness/internal/auth/authz" "github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/services/importer"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/url" "github.com/harness/gitness/internal/url"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
@ -24,7 +25,11 @@ var WireSet = wire.NewSet(
func ProvideController(config *types.Config, db *sqlx.DB, urlProvider *url.Provider, func ProvideController(config *types.Config, db *sqlx.DB, urlProvider *url.Provider,
uidCheck check.PathUID, authorizer authz.Authorizer, pathStore store.PathStore, repoStore store.RepoStore, uidCheck check.PathUID, authorizer authz.Authorizer, pathStore store.PathStore, repoStore store.RepoStore,
spaceStore store.SpaceStore, pipelineStore store.PipelineStore, spaceStore store.SpaceStore, pipelineStore store.PipelineStore,
principalStore store.PrincipalStore, rpcClient gitrpc.Interface) *Controller { principalStore store.PrincipalStore, rpcClient gitrpc.Interface,
return NewController(config.Git.DefaultBranch, db, urlProvider, uidCheck, importer *importer.Repository,
authorizer, pathStore, repoStore, spaceStore, pipelineStore, principalStore, rpcClient) ) *Controller {
return NewController(config.Git.DefaultBranch, db, urlProvider,
uidCheck, authorizer, pathStore, repoStore,
spaceStore, pipelineStore, principalStore, rpcClient,
importer)
} }

View File

@ -7,6 +7,7 @@ package space
import ( import (
"github.com/harness/gitness/internal/api/controller/repo" "github.com/harness/gitness/internal/api/controller/repo"
"github.com/harness/gitness/internal/auth/authz" "github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/url" "github.com/harness/gitness/internal/url"
"github.com/harness/gitness/types/check" "github.com/harness/gitness/types/check"
@ -17,6 +18,7 @@ import (
type Controller struct { type Controller struct {
db *sqlx.DB db *sqlx.DB
urlProvider *url.Provider urlProvider *url.Provider
eventsStream events.EventsStreamer
uidCheck check.PathUID uidCheck check.PathUID
authorizer authz.Authorizer authorizer authz.Authorizer
pathStore store.PathStore pathStore store.PathStore
@ -31,7 +33,7 @@ type Controller struct {
membershipStore store.MembershipStore membershipStore store.MembershipStore
} }
func NewController(db *sqlx.DB, urlProvider *url.Provider, func NewController(db *sqlx.DB, urlProvider *url.Provider, eventsStream events.EventsStreamer,
uidCheck check.PathUID, authorizer authz.Authorizer, uidCheck check.PathUID, authorizer authz.Authorizer,
pathStore store.PathStore, pipelineStore store.PipelineStore, secretStore store.SecretStore, pathStore store.PathStore, pipelineStore store.PipelineStore, secretStore store.SecretStore,
connectorStore store.ConnectorStore, templateStore store.TemplateStore, spaceStore store.SpaceStore, connectorStore store.ConnectorStore, templateStore store.TemplateStore, spaceStore store.SpaceStore,
@ -41,6 +43,7 @@ func NewController(db *sqlx.DB, urlProvider *url.Provider,
return &Controller{ return &Controller{
db: db, db: db,
urlProvider: urlProvider, urlProvider: urlProvider,
eventsStream: eventsStream,
uidCheck: uidCheck, uidCheck: uidCheck,
authorizer: authorizer, authorizer: authorizer,
pathStore: pathStore, pathStore: pathStore,

View File

@ -0,0 +1,93 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package space
import (
"context"
"encoding/json"
"fmt"
"io"
"time"
apiauth "github.com/harness/gitness/internal/api/auth"
"github.com/harness/gitness/internal/auth"
"github.com/harness/gitness/internal/writer"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log"
)
var (
pingInterval = 30 * time.Second
tailMaxTime = 2 * time.Hour
)
func (c *Controller) Events(
ctx context.Context,
session *auth.Session,
spaceRef string,
w writer.WriterFlusher,
) error {
space, err := c.spaceStore.FindByRef(ctx, spaceRef)
if err != nil {
return fmt.Errorf("failed to find space ref: %w", err)
}
if err = apiauth.CheckSpace(ctx, c.authorizer, session, space, enum.PermissionSpaceView, true); err != nil {
return fmt.Errorf("failed to authorize stream: %w", err)
}
ctx, cancel := context.WithTimeout(ctx, tailMaxTime)
defer cancel()
io.WriteString(w, ": ping\n\n")
w.Flush()
events, errc, consumer := c.eventsStream.Subscribe(ctx, space.ID)
defer c.eventsStream.Unsubscribe(ctx, consumer)
// could not get error channel
if errc == nil {
io.WriteString(w, "event: error\ndata: eof\n\n")
w.Flush()
return fmt.Errorf("could not get error channel")
}
pingTimer := time.NewTimer(pingInterval)
defer pingTimer.Stop()
enc := json.NewEncoder(w)
L:
for {
// ensure timer is stopped before resetting (see documentation)
if !pingTimer.Stop() {
// in this specific case the timer's channel could be both, empty or full
select {
case <-pingTimer.C:
default:
}
}
pingTimer.Reset(pingInterval)
select {
case <-ctx.Done():
log.Debug().Msg("events: stream cancelled")
break L
case err := <-errc:
log.Err(err).Msg("events: received error in the tail channel")
break L
case <-pingTimer.C:
// if time b/w messages takes longer, send a ping
io.WriteString(w, ": ping\n\n")
w.Flush()
case event := <-events:
io.WriteString(w, "data: ")
enc.Encode(event)
io.WriteString(w, "\n\n")
w.Flush()
}
}
io.WriteString(w, "event: error\ndata: eof\n\n")
w.Flush()
log.Debug().Msg("events: stream closed")
return nil
}

View File

@ -7,6 +7,7 @@ package space
import ( import (
"github.com/harness/gitness/internal/api/controller/repo" "github.com/harness/gitness/internal/api/controller/repo"
"github.com/harness/gitness/internal/auth/authz" "github.com/harness/gitness/internal/auth/authz"
"github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/url" "github.com/harness/gitness/internal/url"
"github.com/harness/gitness/types/check" "github.com/harness/gitness/types/check"
@ -20,13 +21,14 @@ var WireSet = wire.NewSet(
ProvideController, ProvideController,
) )
func ProvideController(db *sqlx.DB, urlProvider *url.Provider, uidCheck check.PathUID, authorizer authz.Authorizer, func ProvideController(db *sqlx.DB, urlProvider *url.Provider, eventsStream events.EventsStreamer,
pathStore store.PathStore, pipelineStore store.PipelineStore, secretStore store.SecretStore, uidCheck check.PathUID, authorizer authz.Authorizer, pathStore store.PathStore,
pipelineStore store.PipelineStore, secretStore store.SecretStore,
connectorStore store.ConnectorStore, templateStore store.TemplateStore, connectorStore store.ConnectorStore, templateStore store.TemplateStore,
spaceStore store.SpaceStore, repoStore store.RepoStore, principalStore store.PrincipalStore, spaceStore store.SpaceStore, repoStore store.RepoStore, principalStore store.PrincipalStore,
repoCtrl *repo.Controller, membershipStore store.MembershipStore, repoCtrl *repo.Controller, membershipStore store.MembershipStore,
) *Controller { ) *Controller {
return NewController(db, urlProvider, uidCheck, authorizer, return NewController(db, urlProvider, eventsStream, uidCheck, authorizer,
pathStore, pipelineStore, secretStore, connectorStore, templateStore, pathStore, pipelineStore, secretStore, connectorStore, templateStore,
spaceStore, repoStore, principalStore, repoCtrl, membershipStore) spaceStore, repoStore, principalStore, repoCtrl, membershipStore)
} }

View File

@ -60,6 +60,13 @@ func HandleTail(logCtrl *logs.Controller) http.HandlerFunc {
return return
} }
h := w.Header()
h.Set("Content-Type", "text/event-stream")
h.Set("Cache-Control", "no-cache")
h.Set("Connection", "keep-alive")
h.Set("X-Accel-Buffering", "no")
h.Set("Access-Control-Allow-Origin", "*")
io.WriteString(w, ": ping\n\n") io.WriteString(w, ": ping\n\n")
f.Flush() f.Flush()
@ -77,13 +84,6 @@ func HandleTail(logCtrl *logs.Controller) http.HandlerFunc {
return return
} }
h := w.Header()
h.Set("Content-Type", "text/event-stream")
h.Set("Cache-Control", "no-cache")
h.Set("Connection", "keep-alive")
h.Set("X-Accel-Buffering", "no")
h.Set("Access-Control-Allow-Origin", "*")
ctx, cancel := context.WithTimeout(r.Context(), tailMaxTime) ctx, cancel := context.WithTimeout(r.Context(), tailMaxTime)
defer cancel() defer cancel()

View File

@ -0,0 +1,36 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package repo
import (
"encoding/json"
"net/http"
"github.com/harness/gitness/internal/api/controller/repo"
"github.com/harness/gitness/internal/api/render"
"github.com/harness/gitness/internal/api/request"
)
func HandleImport(repoCtrl *repo.Controller) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
in := new(repo.ImportInput)
err := json.NewDecoder(r.Body).Decode(in)
if err != nil {
render.BadRequestf(w, "Invalid Request Body: %s.", err)
return
}
repo, err := repoCtrl.Import(ctx, session, in)
if err != nil {
render.TranslatedUserError(w, err)
return
}
render.JSON(w, http.StatusCreated, repo)
}
}

View File

@ -0,0 +1,33 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package repo
import (
"net/http"
"github.com/harness/gitness/internal/api/controller/repo"
"github.com/harness/gitness/internal/api/render"
"github.com/harness/gitness/internal/api/request"
)
func HandleImportProgress(repoCtrl *repo.Controller) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
repoRef, err := request.GetRepoRefFromPath(r)
if err != nil {
render.TranslatedUserError(w, err)
return
}
progress, err := repoCtrl.ImportProgress(ctx, session, repoRef)
if err != nil {
render.TranslatedUserError(w, err)
return
}
render.JSON(w, http.StatusOK, progress)
}
}

View File

@ -0,0 +1,52 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package space
import (
"net/http"
"github.com/harness/gitness/internal/api/controller/space"
"github.com/harness/gitness/internal/api/render"
"github.com/harness/gitness/internal/api/request"
"github.com/harness/gitness/internal/writer"
"github.com/rs/zerolog/log"
)
// HandleEventsStream returns an http.HandlerFunc that watches for
// events on a space
func HandleEventsStream(spaceCtrl *space.Controller) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
session, _ := request.AuthSessionFrom(ctx)
spaceRef, err := request.GetSpaceRefFromPath(r)
if err != nil {
render.TranslatedUserError(w, err)
return
}
h := w.Header()
h.Set("Content-Type", "text/event-stream")
h.Set("Cache-Control", "no-cache")
h.Set("Connection", "keep-alive")
h.Set("X-Accel-Buffering", "no")
h.Set("Access-Control-Allow-Origin", "*")
f, ok := w.(http.Flusher)
if !ok {
log.Error().Msg("http writer type assertion failed")
render.InternalError(w)
return
}
writer := writer.NewWriterFlusher(w, f)
err = spaceCtrl.Events(ctx, session, spaceRef, writer)
if err != nil {
render.TranslatedUserError(w, err)
return
}
}
}

View File

@ -7,12 +7,12 @@ package openapi
import ( import (
"net/http" "net/http"
"github.com/gotidy/ptr"
"github.com/harness/gitness/internal/api/controller/user" "github.com/harness/gitness/internal/api/controller/user"
"github.com/harness/gitness/internal/api/request" "github.com/harness/gitness/internal/api/request"
"github.com/harness/gitness/internal/api/usererror" "github.com/harness/gitness/internal/api/usererror"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
"github.com/gotidy/ptr"
"github.com/swaggest/openapi-go/openapi3" "github.com/swaggest/openapi-go/openapi3"
) )

View File

@ -0,0 +1,83 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package events
import (
"context"
"encoding/json"
"strconv"
"github.com/harness/gitness/pubsub"
"github.com/harness/gitness/types/enum"
)
// Event is an event which is sent to the UI via server-sent events.
type Event struct {
Type enum.EventType `json:"type"`
Data json.RawMessage `json:"data"`
}
type EventsStreamer interface {
// Publish publishes an event to a given space ID.
Publish(ctx context.Context, spaceID int64, event *Event) error
// Subscribe listens to events on a space ID.
Subscribe(ctx context.Context, spaceID int64) (<-chan *Event, <-chan error, pubsub.Consumer)
// Unsubscribe unsubscribes the consumer.
Unsubscribe(ctx context.Context, consumer pubsub.Consumer) error
}
type event struct {
pubsub pubsub.PubSub
topic string
}
func New(pubsub pubsub.PubSub, topic string) EventsStreamer {
return &event{
pubsub: pubsub,
topic: topic,
}
}
func (e *event) Publish(ctx context.Context, spaceID int64, event *Event) error {
bytes, err := json.Marshal(event)
if err != nil {
return err
}
option := pubsub.WithPublishNamespace(format(spaceID))
return e.pubsub.Publish(ctx, e.topic, bytes, option)
}
// format creates the namespace name which will be spaces-<id>
func format(id int64) string {
return "spaces-" + strconv.Itoa(int(id))
}
func (e *event) Subscribe(ctx context.Context, spaceID int64) (<-chan *Event, <-chan error, pubsub.Consumer) {
chEvent := make(chan *Event, 100) // TODO: check best size here
chErr := make(chan error)
g := func(payload []byte) error {
event := &Event{}
err := json.Unmarshal(payload, event)
if err != nil {
// This should never happen
return err
}
select {
case chEvent <- event:
default:
}
return nil
}
option := pubsub.WithChannelNamespace(format(spaceID))
consumer := e.pubsub.Subscribe(ctx, e.topic, g, option)
return chEvent, chErr, consumer
}
func (e *event) Unsubscribe(ctx context.Context, consumer pubsub.Consumer) error {
return consumer.Unsubscribe(ctx, e.topic)
}

View File

@ -0,0 +1,23 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package events
import (
"github.com/harness/gitness/pubsub"
"github.com/google/wire"
)
// WireSet provides a wire set for this package.
var WireSet = wire.NewSet(
ProvideEventsStreaming,
)
func ProvideEventsStreaming(pubsub pubsub.PubSub) EventsStreamer {
return &event{
pubsub: pubsub,
topic: "events",
}
}

View File

@ -11,6 +11,7 @@ import (
"io" "io"
"time" "time"
"github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/pipeline/file" "github.com/harness/gitness/internal/pipeline/file"
"github.com/harness/gitness/internal/pipeline/scheduler" "github.com/harness/gitness/internal/pipeline/scheduler"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
@ -98,7 +99,7 @@ type Manager struct {
Pipelines store.PipelineStore Pipelines store.PipelineStore
urlProvider *urlprovider.Provider urlProvider *urlprovider.Provider
// Converter store.ConvertService // Converter store.ConvertService
// Events store.Pubsub Events events.EventsStreamer
// Globals store.GlobalSecretStore // Globals store.GlobalSecretStore
Logs store.LogStore Logs store.LogStore
Logz livelog.LogStream Logz livelog.LogStream
@ -119,6 +120,7 @@ func New(
executionStore store.ExecutionStore, executionStore store.ExecutionStore,
pipelineStore store.PipelineStore, pipelineStore store.PipelineStore,
urlProvider *urlprovider.Provider, urlProvider *urlprovider.Provider,
events events.EventsStreamer,
fileService file.FileService, fileService file.FileService,
logStore store.LogStore, logStore store.LogStore,
logStream livelog.LogStream, logStream livelog.LogStream,
@ -134,6 +136,7 @@ func New(
Executions: executionStore, Executions: executionStore,
Pipelines: pipelineStore, Pipelines: pipelineStore,
urlProvider: urlProvider, urlProvider: urlProvider,
Events: events,
FileService: fileService, FileService: fileService,
Logs: logStore, Logs: logStore,
Logz: logStream, Logz: logStream,
@ -313,6 +316,7 @@ func (m *Manager) BeforeStep(ctx context.Context, step *types.Step) error {
} }
updater := &updater{ updater := &updater{
Executions: m.Executions, Executions: m.Executions,
Events: m.Events,
Repos: m.Repos, Repos: m.Repos,
Steps: m.Steps, Steps: m.Steps,
Stages: m.Stages, Stages: m.Stages,
@ -332,6 +336,7 @@ func (m *Manager) AfterStep(ctx context.Context, step *types.Step) error {
var retErr error var retErr error
updater := &updater{ updater := &updater{
Executions: m.Executions, Executions: m.Executions,
Events: m.Events,
Repos: m.Repos, Repos: m.Repos,
Steps: m.Steps, Steps: m.Steps,
Stages: m.Stages, Stages: m.Stages,
@ -352,6 +357,7 @@ func (m *Manager) AfterStep(ctx context.Context, step *types.Step) error {
func (m *Manager) BeforeStage(ctx context.Context, stage *types.Stage) error { func (m *Manager) BeforeStage(ctx context.Context, stage *types.Stage) error {
s := &setup{ s := &setup{
Executions: m.Executions, Executions: m.Executions,
Events: m.Events,
Repos: m.Repos, Repos: m.Repos,
Steps: m.Steps, Steps: m.Steps,
Stages: m.Stages, Stages: m.Stages,
@ -365,6 +371,7 @@ func (m *Manager) BeforeStage(ctx context.Context, stage *types.Stage) error {
func (m *Manager) AfterStage(ctx context.Context, stage *types.Stage) error { func (m *Manager) AfterStage(ctx context.Context, stage *types.Stage) error {
t := &teardown{ t := &teardown{
Executions: m.Executions, Executions: m.Executions,
Events: m.Events,
Logs: m.Logz, Logs: m.Logz,
Repos: m.Repos, Repos: m.Repos,
Scheduler: m.Scheduler, Scheduler: m.Scheduler,

View File

@ -6,9 +6,11 @@ package manager
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"time" "time"
"github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
gitness_store "github.com/harness/gitness/store" gitness_store "github.com/harness/gitness/store"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
@ -19,6 +21,7 @@ import (
type setup struct { type setup struct {
Executions store.ExecutionStore Executions store.ExecutionStore
Events events.EventsStreamer
Repos store.RepoStore Repos store.RepoStore
Steps store.StepStore Steps store.StepStore
Stages store.StageStore Stages store.StageStore
@ -39,7 +42,7 @@ func (s *setup) do(ctx context.Context, stage *types.Stage) error {
Int64("repo.id", execution.RepoID). Int64("repo.id", execution.RepoID).
Logger() Logger()
_, err = s.Repos.Find(noContext, execution.RepoID) repo, err := s.Repos.Find(noContext, execution.RepoID)
if err != nil { if err != nil {
log.Error().Err(err).Msg("manager: cannot find the repository") log.Error().Err(err).Msg("manager: cannot find the repository")
return err return err
@ -72,15 +75,37 @@ func (s *setup) do(ctx context.Context, stage *types.Stage) error {
} }
} }
_, err = s.updateExecution(ctx, execution) _, err = s.updateExecution(noContext, execution)
if err != nil { if err != nil {
log.Error().Err(err).Msg("manager: cannot update the execution") log.Error().Err(err).Msg("manager: cannot update the execution")
return err return err
} }
stages, err := s.Stages.ListWithSteps(noContext, execution.ID)
if err != nil {
log.Error().Err(err).Msg("manager: could not list stages with steps")
return err
}
execution.Stages = stages
err = s.Events.Publish(noContext, repo.ParentID, executionEvent(enum.ExecutionRunning, execution))
if err != nil {
log.Warn().Err(err).Msg("manager: could not publish execution event")
}
return nil return nil
} }
func executionEvent(
eventType enum.EventType,
execution *types.Execution,
) *events.Event {
// json.Marshal will not return an error here, it can be absorbed
bytes, _ := json.Marshal(execution)
return &events.Event{
Type: eventType,
Data: bytes,
}
}
// helper function that updates the execution status from pending to running. // helper function that updates the execution status from pending to running.
// This accounts for the fact that another agent may have already updated // This accounts for the fact that another agent may have already updated
// the execution status, which may happen if two stages execute concurrently. // the execution status, which may happen if two stages execute concurrently.

View File

@ -8,6 +8,7 @@ import (
"context" "context"
"time" "time"
"github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/pipeline/scheduler" "github.com/harness/gitness/internal/pipeline/scheduler"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/livelog" "github.com/harness/gitness/livelog"
@ -20,6 +21,7 @@ import (
type teardown struct { type teardown struct {
Executions store.ExecutionStore Executions store.ExecutionStore
Events events.EventsStreamer
Logs livelog.LogStream Logs livelog.LogStream
Scheduler scheduler.Scheduler Scheduler scheduler.Scheduler
Repos store.RepoStore Repos store.RepoStore
@ -46,7 +48,7 @@ func (t *teardown) do(ctx context.Context, stage *types.Stage) error {
Str("stage.status", stage.Status). Str("stage.status", stage.Status).
Logger() Logger()
_, err = t.Repos.Find(noContext, execution.RepoID) repo, err := t.Repos.Find(noContext, execution.RepoID)
if err != nil { if err != nil {
log.Error().Err(err).Msg("manager: cannot find the repository") log.Error().Err(err).Msg("manager: cannot find the repository")
return err return err
@ -131,6 +133,13 @@ func (t *teardown) do(ctx context.Context, stage *types.Stage) error {
return err return err
} }
execution.Stages = stages
err = t.Events.Publish(noContext, repo.ParentID, executionEvent(enum.ExecutionCompleted, execution))
if err != nil {
log.Warn().Err(err).
Msg("manager: could not publish execution completed event")
}
return nil return nil
} }

View File

@ -7,8 +7,10 @@ package manager
import ( import (
"context" "context"
"github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
"github.com/harness/gitness/types" "github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
@ -16,6 +18,7 @@ import (
type updater struct { type updater struct {
Executions store.ExecutionStore Executions store.ExecutionStore
Repos store.RepoStore Repos store.RepoStore
Events events.EventsStreamer
Steps store.StepStore Steps store.StepStore
Stages store.StageStore Stages store.StageStore
} }
@ -36,5 +39,35 @@ func (u *updater) do(ctx context.Context, step *types.Step) error {
return err return err
} }
stage, err := u.Stages.Find(noContext, step.StageID)
if err != nil {
log.Error().Err(err).Msg("manager: cannot find stage")
return nil
}
execution, err := u.Executions.Find(noContext, stage.ExecutionID)
if err != nil {
log.Error().Err(err).Msg("manager: cannot find execution")
return nil
}
repo, err := u.Repos.Find(noContext, execution.RepoID)
if err != nil {
log.Error().Err(err).Msg("manager: cannot find repo")
return nil
}
stages, err := u.Stages.ListWithSteps(noContext, stage.ExecutionID)
if err != nil {
log.Error().Err(err).Msg("manager: cannot find stages")
return nil
}
execution.Stages = stages
err = u.Events.Publish(noContext, repo.ParentID, executionEvent(enum.ExecutionUpdated, execution))
if err != nil {
log.Warn().Err(err).Msg("manager: cannot publish execution updated event")
}
return nil return nil
} }

View File

@ -5,6 +5,7 @@
package manager package manager
import ( import (
"github.com/harness/gitness/internal/pipeline/events"
"github.com/harness/gitness/internal/pipeline/file" "github.com/harness/gitness/internal/pipeline/file"
"github.com/harness/gitness/internal/pipeline/scheduler" "github.com/harness/gitness/internal/pipeline/scheduler"
"github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store"
@ -28,6 +29,7 @@ func ProvideExecutionManager(
executionStore store.ExecutionStore, executionStore store.ExecutionStore,
pipelineStore store.PipelineStore, pipelineStore store.PipelineStore,
urlProvider *url.Provider, urlProvider *url.Provider,
events events.EventsStreamer,
fileService file.FileService, fileService file.FileService,
logStore store.LogStore, logStore store.LogStore,
logStream livelog.LogStream, logStream livelog.LogStream,
@ -37,7 +39,7 @@ func ProvideExecutionManager(
stageStore store.StageStore, stageStore store.StageStore,
stepStore store.StepStore, stepStore store.StepStore,
userStore store.PrincipalStore) ExecutionManager { userStore store.PrincipalStore) ExecutionManager {
return New(config, executionStore, pipelineStore, urlProvider, fileService, logStore, return New(config, executionStore, pipelineStore, urlProvider, events, fileService, logStore,
logStream, repoStore, scheduler, secretStore, stageStore, stepStore, userStore) logStream, repoStore, scheduler, secretStore, stageStore, stepStore, userStore)
} }

View File

@ -188,6 +188,8 @@ func setupSpaces(r chi.Router, spaceCtrl *space.Controller) {
r.Patch("/", handlerspace.HandleUpdate(spaceCtrl)) r.Patch("/", handlerspace.HandleUpdate(spaceCtrl))
r.Delete("/", handlerspace.HandleDelete(spaceCtrl)) r.Delete("/", handlerspace.HandleDelete(spaceCtrl))
r.Get("/stream", handlerspace.HandleEventsStream(spaceCtrl))
r.Post("/move", handlerspace.HandleMove(spaceCtrl)) r.Post("/move", handlerspace.HandleMove(spaceCtrl))
r.Get("/spaces", handlerspace.HandleListSpaces(spaceCtrl)) r.Get("/spaces", handlerspace.HandleListSpaces(spaceCtrl))
r.Get("/repos", handlerspace.HandleListRepos(spaceCtrl)) r.Get("/repos", handlerspace.HandleListRepos(spaceCtrl))
@ -232,6 +234,7 @@ func setupRepos(r chi.Router,
r.Route("/repos", func(r chi.Router) { r.Route("/repos", func(r chi.Router) {
// Create takes path and parentId via body, not uri // Create takes path and parentId via body, not uri
r.Post("/", handlerrepo.HandleCreate(repoCtrl)) r.Post("/", handlerrepo.HandleCreate(repoCtrl))
r.Post("/import", handlerrepo.HandleImport(repoCtrl))
r.Route(fmt.Sprintf("/{%s}", request.PathParamRepoRef), func(r chi.Router) { r.Route(fmt.Sprintf("/{%s}", request.PathParamRepoRef), func(r chi.Router) {
// repo level operations // repo level operations
r.Get("/", handlerrepo.HandleFind(repoCtrl)) r.Get("/", handlerrepo.HandleFind(repoCtrl))
@ -241,6 +244,8 @@ func setupRepos(r chi.Router,
r.Post("/move", handlerrepo.HandleMove(repoCtrl)) r.Post("/move", handlerrepo.HandleMove(repoCtrl))
r.Get("/service-accounts", handlerrepo.HandleListServiceAccounts(repoCtrl)) r.Get("/service-accounts", handlerrepo.HandleListServiceAccounts(repoCtrl))
r.Get("/import-progress", handlerrepo.HandleImportProgress(repoCtrl))
// content operations // content operations
// NOTE: this allows /content and /content/ to both be valid (without any other tricks.) // NOTE: this allows /content and /content/ to both be valid (without any other tricks.)
// We don't expect there to be any other operations in that route (as that could overlap with file names) // We don't expect there to be any other operations in that route (as that could overlap with file names)

View File

@ -0,0 +1,142 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package importer
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/harness/gitness/internal/api/usererror"
"github.com/drone/go-scm/scm"
"github.com/drone/go-scm/scm/driver/github"
"github.com/drone/go-scm/scm/transport/oauth2"
)
type ProviderType string
const (
ProviderTypeGitHub ProviderType = "github"
)
type ProviderInfo struct {
Type ProviderType
Host string
User string
Pass string
}
type RepositoryInfo struct {
Space string
UID string
CloneURL string
IsPublic bool
DefaultBranch string
}
func getClient(provider ProviderInfo) (*scm.Client, error) {
var scmClient *scm.Client
switch provider.Type {
case "":
return nil, usererror.BadRequest("provider can not be empty")
case ProviderTypeGitHub:
scmClient = github.NewDefault()
if provider.Pass != "" {
scmClient.Client = &http.Client{
Transport: &oauth2.Transport{
Source: oauth2.StaticTokenSource(&scm.Token{Token: provider.Pass}),
},
}
}
default:
return nil, usererror.BadRequestf("unsupported provider: %s", provider)
}
return scmClient, nil
}
func Repo(ctx context.Context, provider ProviderInfo, repoSlug string) (RepositoryInfo, error) {
scmClient, err := getClient(provider)
if err != nil {
return RepositoryInfo{}, err
}
scmRepo, _, err := scmClient.Repositories.Find(ctx, repoSlug)
if errors.Is(err, scm.ErrNotFound) {
return RepositoryInfo{}, usererror.BadRequestf("repository %s not found at %s", repoSlug, provider)
}
if errors.Is(err, scm.ErrNotAuthorized) {
return RepositoryInfo{}, usererror.BadRequestf("bad credentials provided for %s at %s", repoSlug, provider)
}
if err != nil {
return RepositoryInfo{}, fmt.Errorf("failed to fetch repository %s from %s: %w", repoSlug, provider, err)
}
return RepositoryInfo{
Space: scmRepo.Namespace,
UID: scmRepo.Name,
CloneURL: scmRepo.Clone,
IsPublic: !scmRepo.Private,
DefaultBranch: scmRepo.Branch,
}, nil
}
func Space(ctx context.Context, provider ProviderInfo, space string) (map[string]RepositoryInfo, error) {
scmClient, err := getClient(provider)
if err != nil {
return nil, err
}
repoMap := make(map[string]RepositoryInfo)
const pageSize = 50
page := 1
for {
scmRepos, scmResponse, err := scmClient.Repositories.ListV2(ctx, scm.RepoListOptions{
ListOptions: scm.ListOptions{
URL: "",
Page: page,
Size: pageSize,
},
RepoSearchTerm: scm.RepoSearchTerm{
RepoName: "",
User: space,
},
})
if errors.Is(err, scm.ErrNotFound) {
return nil, usererror.BadRequestf("space %s not found at %s", space, provider)
}
if errors.Is(err, scm.ErrNotAuthorized) {
return nil, usererror.BadRequestf("bad credentials provided for %s at %s", space, provider)
}
if err != nil {
return nil, fmt.Errorf("failed to fetch space %s from %s: %w", space, provider, err)
}
for _, scmRepo := range scmRepos {
if !scmRepo.Perm.Pull {
continue
}
repoMap[scmRepo.Name] = RepositoryInfo{
Space: scmRepo.Namespace,
UID: scmRepo.Name,
CloneURL: scmRepo.Clone,
IsPublic: !scmRepo.Private,
DefaultBranch: scmRepo.Branch,
}
}
if len(scmRepos) == 0 || page == scmResponse.Page.Last {
break
}
page++
}
return repoMap, nil
}

View File

@ -0,0 +1,165 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package importer
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/url"
"strings"
"time"
"github.com/harness/gitness/gitrpc"
"github.com/harness/gitness/internal/bootstrap"
"github.com/harness/gitness/internal/githook"
"github.com/harness/gitness/internal/services/job"
"github.com/harness/gitness/internal/store"
gitnessurl "github.com/harness/gitness/internal/url"
gitness_store "github.com/harness/gitness/store"
"github.com/harness/gitness/types"
)
type Repository struct {
urlProvider *gitnessurl.Provider
git gitrpc.Interface
repoStore store.RepoStore
scheduler *job.Scheduler
}
var _ job.Handler = (*Repository)(nil)
type Input struct {
RepoID int64 `json:"repo_id"`
GitUser string `json:"git_user"`
GitPass string `json:"git_pass"`
CloneURL string `json:"clone_url"`
}
const jobType = "repository_import"
func (i *Repository) Register(executor *job.Executor) error {
return executor.Register(jobType, i)
}
func (i *Repository) Run(ctx context.Context, jobUID string, input Input) error {
data, err := json.Marshal(input)
if err != nil {
return err
}
strData := strings.TrimSpace(string(data))
return i.scheduler.RunJob(ctx, job.Definition{
UID: jobUID,
Type: jobType,
MaxRetries: 1,
Timeout: 30 * time.Minute,
Data: strData,
})
}
// Handle is repository import background job handler.
func (i *Repository) Handle(ctx context.Context, data string, _ job.ProgressReporter) (string, error) {
var input Input
if err := json.NewDecoder(strings.NewReader(data)).Decode(&input); err != nil {
return "", fmt.Errorf("failed to unmarshal job input: %w", err)
}
if input.CloneURL == "" {
return "", errors.New("missing git repository clone URL")
}
if input.GitUser != "" || input.GitPass != "" {
repoURL, err := url.Parse(input.CloneURL)
if err != nil {
return "", fmt.Errorf("failed to parse git clone URL: %w", err)
}
repoURL.User = url.UserPassword(input.GitUser, input.GitPass)
input.CloneURL = repoURL.String()
}
repo, err := i.repoStore.Find(ctx, input.RepoID)
if err != nil {
return "", fmt.Errorf("failed to find repo by id: %w", err)
}
if !repo.Importing {
return "", fmt.Errorf("repository %s is not being imported", repo.UID)
}
writeParams, err := createRPCWriteParams(ctx, i.urlProvider, repo)
if err != nil {
return "", fmt.Errorf("failed to create write params: %w", err)
}
syncOut, err := i.git.SyncRepository(ctx, &gitrpc.SyncRepositoryParams{
WriteParams: writeParams,
Source: input.CloneURL,
CreateIfNotExists: false,
})
if err != nil {
return "", fmt.Errorf("failed to sync repositories: %w", err)
}
repo.Importing = false
repo.DefaultBranch = syncOut.DefaultBranch
err = i.repoStore.Update(ctx, repo)
if err != nil {
return "", fmt.Errorf("failed to update repository after import: %w", err)
}
return "", err
}
func (i *Repository) GetProgress(ctx context.Context, repo *types.Repository) (types.JobProgress, error) {
if !repo.Importing || repo.ImportingJobUID == nil || *repo.ImportingJobUID == "" {
// if the repo is not being imported, or it's job ID has been cleared (or never existed) return state=finished
return job.DoneProgress(), nil
}
progress, err := i.scheduler.GetJobProgress(ctx, *repo.ImportingJobUID)
if errors.Is(err, gitness_store.ErrResourceNotFound) {
// if the job is not found return state=failed
return job.FailProgress(), nil
}
if err != nil {
return types.JobProgress{}, fmt.Errorf("failed to get job progress: %w", err)
}
return progress, nil
}
// CreateRPCWriteParams creates base write parameters for gitrpc write operations.
func createRPCWriteParams(ctx context.Context,
urlProvider *gitnessurl.Provider,
repo *types.Repository,
) (gitrpc.WriteParams, error) {
gitnessSession := bootstrap.NewSystemServiceSession()
// generate envars (add everything githook CLI needs for execution)
envVars, err := githook.GenerateEnvironmentVariables(
ctx,
urlProvider.GetAPIBaseURLInternal(),
repo.ID,
gitnessSession.Principal.ID,
false,
)
if err != nil {
return gitrpc.WriteParams{}, fmt.Errorf("failed to generate git hook environment variables: %w", err)
}
return gitrpc.WriteParams{
Actor: gitrpc.Identity{
Name: gitnessSession.Principal.DisplayName,
Email: gitnessSession.Principal.Email,
},
RepoUID: repo.GitUID,
EnvVars: envVars,
}, nil
}

View File

@ -0,0 +1,40 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package importer
import (
"github.com/harness/gitness/gitrpc"
"github.com/harness/gitness/internal/services/job"
"github.com/harness/gitness/internal/store"
"github.com/harness/gitness/internal/url"
"github.com/google/wire"
)
var WireSet = wire.NewSet(
ProvideRepoImporter,
)
func ProvideRepoImporter(
urlProvider *url.Provider,
git gitrpc.Interface,
repoStore store.RepoStore,
scheduler *job.Scheduler,
executor *job.Executor,
) (*Repository, error) {
importer := &Repository{
urlProvider: urlProvider,
git: git,
repoStore: repoStore,
scheduler: scheduler,
}
err := executor.Register(jobType, importer)
if err != nil {
return nil, err
}
return importer, nil
}

View File

@ -0,0 +1,22 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package trigger
import (
"context"
"github.com/harness/gitness/events"
gitevents "github.com/harness/gitness/internal/events/git"
)
func (s *Service) handleEventBranchCreated(ctx context.Context,
event *events.Event[*gitevents.BranchCreatedPayload]) error {
return events.NewDiscardEventErrorf("not implemented")
}
func (s *Service) handleEventBranchUpdated(ctx context.Context,
event *events.Event[*gitevents.BranchUpdatedPayload]) error {
return events.NewDiscardEventErrorf("not implemented")
}

View File

@ -0,0 +1,27 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package trigger
import (
"context"
"github.com/harness/gitness/events"
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
)
func (s *Service) handleEventPullReqCreated(ctx context.Context,
event *events.Event[*pullreqevents.CreatedPayload]) error {
return events.NewDiscardEventErrorf("not implemented")
}
func (s *Service) handleEventPullReqReopened(ctx context.Context,
event *events.Event[*pullreqevents.ReopenedPayload]) error {
return events.NewDiscardEventErrorf("not implemented")
}
func (s *Service) handleEventPullReqBranchUpdated(ctx context.Context,
event *events.Event[*pullreqevents.BranchUpdatedPayload]) error {
return events.NewDiscardEventErrorf("not implemented")
}

View File

@ -0,0 +1,22 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package trigger
import (
"context"
"github.com/harness/gitness/events"
gitevents "github.com/harness/gitness/internal/events/git"
)
func (s *Service) handleEventTagCreated(ctx context.Context,
event *events.Event[*gitevents.TagCreatedPayload]) error {
return events.NewDiscardEventErrorf("not implemented")
}
func (s *Service) handleEventTagUpdated(ctx context.Context,
event *events.Event[*gitevents.TagUpdatedPayload]) error {
return events.NewDiscardEventErrorf("not implemented")
}

View File

@ -0,0 +1,103 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package trigger
import (
"context"
"errors"
"fmt"
"time"
"github.com/harness/gitness/events"
gitevents "github.com/harness/gitness/internal/events/git"
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
"github.com/harness/gitness/stream"
)
const (
eventsReaderGroupName = "gitness:trigger"
)
type Config struct {
EventReaderName string
Concurrency int
MaxRetries int
}
func (c *Config) Prepare() error {
if c == nil {
return errors.New("config is required")
}
if c.EventReaderName == "" {
return errors.New("config.EventReaderName is required")
}
if c.Concurrency < 1 {
return errors.New("config.Concurrency has to be a positive number")
}
if c.MaxRetries < 0 {
return errors.New("config.MaxRetries can't be negative")
}
return nil
}
type Service struct{}
func New(
ctx context.Context,
config Config,
gitReaderFactory *events.ReaderFactory[*gitevents.Reader],
pullreqEvReaderFactory *events.ReaderFactory[*pullreqevents.Reader],
) (*Service, error) {
if err := config.Prepare(); err != nil {
return nil, fmt.Errorf("provided trigger service config is invalid: %w", err)
}
service := &Service{}
_, err := gitReaderFactory.Launch(ctx, eventsReaderGroupName, config.EventReaderName,
func(r *gitevents.Reader) error {
const idleTimeout = 1 * time.Minute
r.Configure(
stream.WithConcurrency(config.Concurrency),
stream.WithHandlerOptions(
stream.WithIdleTimeout(idleTimeout),
stream.WithMaxRetries(config.MaxRetries),
))
_ = r.RegisterBranchCreated(service.handleEventBranchCreated)
_ = r.RegisterBranchUpdated(service.handleEventBranchUpdated)
_ = r.RegisterTagCreated(service.handleEventTagCreated)
_ = r.RegisterTagUpdated(service.handleEventTagUpdated)
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to launch git events reader: %w", err)
}
_, err = pullreqEvReaderFactory.Launch(ctx, eventsReaderGroupName, config.EventReaderName,
func(r *pullreqevents.Reader) error {
const idleTimeout = 1 * time.Minute
r.Configure(
stream.WithConcurrency(config.Concurrency),
stream.WithHandlerOptions(
stream.WithIdleTimeout(idleTimeout),
stream.WithMaxRetries(config.MaxRetries),
))
_ = r.RegisterCreated(service.handleEventPullReqCreated)
_ = r.RegisterBranchUpdated(service.handleEventPullReqBranchUpdated)
_ = r.RegisterReopened(service.handleEventPullReqReopened)
return nil
})
if err != nil {
return nil, fmt.Errorf("failed to launch pr events reader: %w", err)
}
return service, nil
}

View File

@ -0,0 +1,28 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package trigger
import (
"context"
"github.com/harness/gitness/events"
gitevents "github.com/harness/gitness/internal/events/git"
pullreqevents "github.com/harness/gitness/internal/events/pullreq"
"github.com/google/wire"
)
var WireSet = wire.NewSet(
ProvideService,
)
func ProvideService(
ctx context.Context,
config Config,
gitReaderFactory *events.ReaderFactory[*gitevents.Reader],
pullReqEvFactory *events.ReaderFactory[*pullreqevents.Reader],
) (*Service, error) {
return New(ctx, config, gitReaderFactory, pullReqEvFactory)
}

View File

@ -27,17 +27,15 @@ const (
type Config struct { type Config struct {
// UserAgentIdentity specifies the identity used for the user agent header // UserAgentIdentity specifies the identity used for the user agent header
// IMPORTANT: do not include version. // IMPORTANT: do not include version.
UserAgentIdentity string `envconfig:"GITNESS_WEBHOOK_USER_AGENT_IDENTITY" default:"Gitness"` UserAgentIdentity string
// HeaderIdentity specifies the identity used for headers in webhook calls (e.g. X-Gitness-Trigger, ...). // HeaderIdentity specifies the identity used for headers in webhook calls (e.g. X-Gitness-Trigger, ...).
// NOTE: If no value is provided, the UserAgentIdentity will be used. // NOTE: If no value is provided, the UserAgentIdentity will be used.
HeaderIdentity string `envconfig:"GITNESS_WEBHOOK_HEADER_IDENTITY"` HeaderIdentity string
// EventReaderName is the name used to read events from stream. EventReaderName string
// Note: this should be different for every running instance. Concurrency int
EventReaderName string `envconfig:"GITNESS_WEBHOOK_EVENT_READER_NAME"` MaxRetries int
Concurrency int `envconfig:"GITNESS_WEBHOOK_CONCURRENCY" default:"4"` AllowPrivateNetwork bool
MaxRetries int `envconfig:"GITNESS_WEBHOOK_MAX_RETRIES" default:"3"` AllowLoopback bool
AllowPrivateNetwork bool `envconfig:"GITNESS_WEBHOOK_ALLOW_PRIVATE_NETWORK" default:"false"`
AllowLoopback bool `envconfig:"GITNESS_WEBHOOK_ALLOW_LOOPBACK" default:"false"`
} }
func (c *Config) Prepare() error { func (c *Config) Prepare() error {
@ -91,7 +89,7 @@ func NewService(ctx context.Context, config Config,
repoStore store.RepoStore, pullreqStore store.PullReqStore, urlProvider *url.Provider, repoStore store.RepoStore, pullreqStore store.PullReqStore, urlProvider *url.Provider,
principalStore store.PrincipalStore, gitRPCClient gitrpc.Interface) (*Service, error) { principalStore store.PrincipalStore, gitRPCClient gitrpc.Interface) (*Service, error) {
if err := config.Prepare(); err != nil { if err := config.Prepare(); err != nil {
return nil, fmt.Errorf("provided config is invalid: %w", err) return nil, fmt.Errorf("provided webhook service config is invalid: %w", err)
} }
service := &Service{ service := &Service{
webhookStore: webhookStore, webhookStore: webhookStore,

View File

@ -7,6 +7,7 @@ package services
import ( import (
"github.com/harness/gitness/internal/services/job" "github.com/harness/gitness/internal/services/job"
"github.com/harness/gitness/internal/services/pullreq" "github.com/harness/gitness/internal/services/pullreq"
"github.com/harness/gitness/internal/services/trigger"
"github.com/harness/gitness/internal/services/webhook" "github.com/harness/gitness/internal/services/webhook"
"github.com/google/wire" "github.com/google/wire"
@ -19,20 +20,20 @@ var WireSet = wire.NewSet(
type Services struct { type Services struct {
Webhook *webhook.Service Webhook *webhook.Service
PullReq *pullreq.Service PullReq *pullreq.Service
JobExecutor *job.Executor Trigger *trigger.Service
JobScheduler *job.Scheduler JobScheduler *job.Scheduler
} }
func ProvideServices( func ProvideServices(
webhooksSrv *webhook.Service, webhooksSvc *webhook.Service,
pullReqSrv *pullreq.Service, pullReqSvc *pullreq.Service,
jobExecutor *job.Executor, triggerSvc *trigger.Service,
jobScheduler *job.Scheduler, jobScheduler *job.Scheduler,
) Services { ) Services {
return Services{ return Services{
Webhook: webhooksSrv, Webhook: webhooksSvc,
PullReq: pullReqSrv, PullReq: pullReqSvc,
JobExecutor: jobExecutor, Trigger: triggerSvc,
JobScheduler: jobScheduler, JobScheduler: jobScheduler,
} }
} }

View File

@ -0,0 +1,4 @@
ALTER TABLE repositories
DROP CONSTRAINT fk_repo_importing_job_uid,
DROP COLUMN repo_importing_job_uid,
DROP COLUMN repo_importing;

View File

@ -0,0 +1,8 @@
ALTER TABLE repositories
ADD COLUMN repo_importing BOOLEAN NOT NULL DEFAULT false,
ADD COLUMN repo_importing_job_uid TEXT,
ADD CONSTRAINT fk_repo_importing_job_uid
FOREIGN KEY (repo_importing_job_uid)
REFERENCES jobs(job_uid)
ON DELETE SET NULL
ON UPDATE NO ACTION;

View File

@ -0,0 +1,2 @@
ALTER TABLE repositories DROP COLUMN repo_importing_job_uid;
ALTER TABLE repositories DROP COLUMN repo_importing;

View File

@ -0,0 +1,2 @@
ALTER TABLE repositories ADD COLUMN repo_importing BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE repositories ADD COLUMN repo_importing_job_uid TEXT;

View File

@ -58,7 +58,9 @@ const (
,repo_num_pulls ,repo_num_pulls
,repo_num_closed_pulls ,repo_num_closed_pulls
,repo_num_open_pulls ,repo_num_open_pulls
,repo_num_merged_pulls` ,repo_num_merged_pulls
,repo_importing
,repo_importing_job_uid`
repoSelectBaseWithJoin = ` repoSelectBaseWithJoin = `
SELECT` + repoColumnsForJoin + ` SELECT` + repoColumnsForJoin + `
@ -124,6 +126,8 @@ func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
,repo_num_closed_pulls ,repo_num_closed_pulls
,repo_num_open_pulls ,repo_num_open_pulls
,repo_num_merged_pulls ,repo_num_merged_pulls
,repo_importing
,repo_importing_job_uid
) values ( ) values (
:repo_version :repo_version
,:repo_parent_id ,:repo_parent_id
@ -142,6 +146,8 @@ func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
,:repo_num_closed_pulls ,:repo_num_closed_pulls
,:repo_num_open_pulls ,:repo_num_open_pulls
,:repo_num_merged_pulls ,:repo_num_merged_pulls
,:repo_importing
,:repo_importing_job_uid
) RETURNING repo_id` ) RETURNING repo_id`
db := dbtx.GetAccessor(ctx, s.db) db := dbtx.GetAccessor(ctx, s.db)
@ -170,12 +176,15 @@ func (s *RepoStore) Update(ctx context.Context, repo *types.Repository) error {
,repo_uid = :repo_uid ,repo_uid = :repo_uid
,repo_description = :repo_description ,repo_description = :repo_description
,repo_is_public = :repo_is_public ,repo_is_public = :repo_is_public
,repo_default_branch = :repo_default_branch
,repo_pullreq_seq = :repo_pullreq_seq ,repo_pullreq_seq = :repo_pullreq_seq
,repo_num_forks = :repo_num_forks ,repo_num_forks = :repo_num_forks
,repo_num_pulls = :repo_num_pulls ,repo_num_pulls = :repo_num_pulls
,repo_num_closed_pulls = :repo_num_closed_pulls ,repo_num_closed_pulls = :repo_num_closed_pulls
,repo_num_open_pulls = :repo_num_open_pulls ,repo_num_open_pulls = :repo_num_open_pulls
,repo_num_merged_pulls = :repo_num_merged_pulls ,repo_num_merged_pulls = :repo_num_merged_pulls
,repo_importing = :repo_importing
,repo_importing_job_uid = :repo_importing_job_uid
WHERE repo_id = :repo_id AND repo_version = :repo_version - 1` WHERE repo_id = :repo_id AND repo_version = :repo_version - 1`
updatedAt := time.Now() updatedAt := time.Now()
@ -295,17 +304,13 @@ func (s *RepoStore) List(ctx context.Context, parentID int64, opts *types.RepoFi
// NOTE: string concatenation is safe because the // NOTE: string concatenation is safe because the
// order attribute is an enum and is not user-defined, // order attribute is an enum and is not user-defined,
// and is therefore not subject to injection attacks. // and is therefore not subject to injection attacks.
stmt = stmt.OrderBy("repo_uid " + opts.Order.String()) stmt = stmt.OrderBy("repo_importing desc, repo_uid " + opts.Order.String())
//TODO: Postgres does not support COLLATE NOCASE for UTF8
// stmt = stmt.OrderBy("repo_uid COLLATE NOCASE " + opts.Order.String())
case enum.RepoAttrCreated: case enum.RepoAttrCreated:
stmt = stmt.OrderBy("repo_created " + opts.Order.String()) stmt = stmt.OrderBy("repo_created " + opts.Order.String())
case enum.RepoAttrUpdated: case enum.RepoAttrUpdated:
stmt = stmt.OrderBy("repo_updated " + opts.Order.String()) stmt = stmt.OrderBy("repo_updated " + opts.Order.String())
case enum.RepoAttrPath: case enum.RepoAttrPath:
stmt = stmt.OrderBy("repo_path " + opts.Order.String()) stmt = stmt.OrderBy("repo_importing desc, repo_path " + opts.Order.String())
//TODO: Postgres does not support COLLATE NOCASE for UTF8
// stmt = stmt.OrderBy("repo_path COLLATE NOCASE " + opts.Order.String())
} }
sql, args, err := stmt.ToSql() sql, args, err := stmt.ToSql()

View File

@ -0,0 +1,37 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package writer
import "io"
type Flusher interface {
Flush()
}
type writeWithFlusher struct {
writer io.Writer
flusher Flusher
}
type WriterFlusher interface {
io.Writer
Flusher
}
func NewWriterFlusher(writer io.Writer, flusher Flusher) WriterFlusher {
return &writeWithFlusher{
writer: writer,
flusher: flusher,
}
}
func (w *writeWithFlusher) Write(p []byte) (int, error) {
n, err := w.writer.Write(p)
return n, err
}
func (w *writeWithFlusher) Flush() {
w.flusher.Flush()
}

View File

@ -200,4 +200,22 @@ type Config struct {
// finished and failed jobs will be purged from the DB. // finished and failed jobs will be purged from the DB.
PurgeFinishedOlderThan time.Duration `envconfig:"GITNESS_JOBS_PURGE_FINISHED_OLDER_THAN" default:"120h"` PurgeFinishedOlderThan time.Duration `envconfig:"GITNESS_JOBS_PURGE_FINISHED_OLDER_THAN" default:"120h"`
} }
Webhook struct {
// UserAgentIdentity specifies the identity used for the user agent header
// IMPORTANT: do not include version.
UserAgentIdentity string `envconfig:"GITNESS_WEBHOOK_USER_AGENT_IDENTITY" default:"Gitness"`
// HeaderIdentity specifies the identity used for headers in webhook calls (e.g. X-Gitness-Trigger, ...).
// NOTE: If no value is provided, the UserAgentIdentity will be used.
HeaderIdentity string `envconfig:"GITNESS_WEBHOOK_HEADER_IDENTITY"`
Concurrency int `envconfig:"GITNESS_WEBHOOK_CONCURRENCY" default:"4"`
MaxRetries int `envconfig:"GITNESS_WEBHOOK_MAX_RETRIES" default:"3"`
AllowPrivateNetwork bool `envconfig:"GITNESS_WEBHOOK_ALLOW_PRIVATE_NETWORK" default:"false"`
AllowLoopback bool `envconfig:"GITNESS_WEBHOOK_ALLOW_LOOPBACK" default:"false"`
}
Trigger struct {
Concurrency int `envconfig:"GITNESS_TRIGGER_CONCURRENCY" default:"4"`
MaxRetries int `envconfig:"GITNESS_TRIGGER_MAX_RETRIES" default:"3"`
}
} }

15
types/enum/event_types.go Normal file
View File

@ -0,0 +1,15 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
// Enums for event types delivered to the event stream for the UI
package enum
// EventType defines the kind of event
type EventType string
const (
ExecutionUpdated = "execution_updated"
ExecutionRunning = "execution_running"
ExecutionCompleted = "execution_completed"
)

View File

@ -35,6 +35,9 @@ type Repository struct {
NumOpenPulls int `db:"repo_num_open_pulls" json:"num_open_pulls"` NumOpenPulls int `db:"repo_num_open_pulls" json:"num_open_pulls"`
NumMergedPulls int `db:"repo_num_merged_pulls" json:"num_merged_pulls"` NumMergedPulls int `db:"repo_num_merged_pulls" json:"num_merged_pulls"`
Importing bool `db:"repo_importing" json:"importing"`
ImportingJobUID *string `db:"repo_importing_job_uid" json:"-"`
// git urls // git urls
GitURL string `db:"-" json:"git_url"` GitURL string `db:"-" json:"git_url"`
} }

View File

@ -57,7 +57,8 @@ const devConfig = {
secure: false, secure: false,
changeOrigin: true changeOrigin: true
} }
} },
compress: false
}, },
plugins: [ plugins: [
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({

View File

@ -61,7 +61,7 @@
"marked": "^4.0.12", "marked": "^4.0.12",
"masonry-layout": "^4.2.2", "masonry-layout": "^4.2.2",
"moment": "^2.25.3", "moment": "^2.25.3",
"monaco-editor": "^0.37.1", "monaco-editor": "^0.40.0",
"monaco-editor-webpack-plugin": "^7.0.1", "monaco-editor-webpack-plugin": "^7.0.1",
"monaco-yaml": "^4.0.4", "monaco-yaml": "^4.0.4",
"qs": "^6.9.4", "qs": "^6.9.4",
@ -72,7 +72,7 @@
"react-intersection-observer": "^9.4.1", "react-intersection-observer": "^9.4.1",
"react-jsx-match": "^1.1.5", "react-jsx-match": "^1.1.5",
"react-keywords": "^0.0.5", "react-keywords": "^0.0.5",
"react-monaco-editor": "^0.52.0", "react-monaco-editor": "^0.54.0",
"react-pdf": "^7.1.2", "react-pdf": "^7.1.2",
"react-resize-detector": "^7.1.2", "react-resize-detector": "^7.1.2",
"react-router-dom": "^5.2.1", "react-router-dom": "^5.2.1",
@ -130,7 +130,6 @@
"identity-obj-proxy": "^3.0.0", "identity-obj-proxy": "^3.0.0",
"jest": "^26.2.0", "jest": "^26.2.0",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"lint-staged": "^11.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mini-css-extract-plugin": "^2.4.2", "mini-css-extract-plugin": "^2.4.2",
"mustache": "^4.0.1", "mustache": "^4.0.1",
@ -157,34 +156,5 @@
}, },
"engines": { "engines": {
"node": ">=14.16.0" "node": ">=14.16.0"
},
"lint-staged": {
"*.{ts,tsx}": [
"eslint --rulesdir ./scripts/eslint-rules --resolve-plugins-relative-to",
"sh scripts/typecheck-staged.sh",
"prettier --check"
],
"*.scss": [
"prettier --check"
],
"strings.*.yaml": [
"npm strings:check"
],
"webpack.devServerProxy.config.js": [
"exit 1"
]
},
"i18nSettings": {
"extensionToLanguageMap": {
"es": [
"es"
],
"en": [
"en",
"en-US",
"en-IN",
"en-UK"
]
}
} }
} }

View File

@ -1,4 +1,5 @@
import React, { useState, useContext, useEffect } from 'react' import React, { useState, useContext, useEffect, useMemo } from 'react'
import { matchPath } from 'react-router-dom'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { useGet } from 'restful-react' import { useGet } from 'restful-react'
import type { AppProps } from 'AppProps' import type { AppProps } from 'AppProps'
@ -33,8 +34,13 @@ export const AppContextProvider: React.FC<{ value: AppProps }> = React.memo(func
value: initialValue, value: initialValue,
children children
}) { }) {
const lazy = useMemo(
() => initialValue.standalone && !!matchPath(location.pathname, { path: '/(signin|register)' }),
[initialValue.standalone]
)
const { data: currentUser = defaultCurrentUser } = useGet({ const { data: currentUser = defaultCurrentUser } = useGet({
path: '/api/v1/user' path: '/api/v1/user',
lazy
}) })
const [appStates, setAppStates] = useState<AppProps>(initialValue) const [appStates, setAppStates] = useState<AppProps>(initialValue)

View File

@ -36,7 +36,6 @@ import AddUpdatePipeline from 'pages/AddUpdatePipeline/AddUpdatePipeline'
export const RouteDestinations: React.FC = React.memo(function RouteDestinations() { export const RouteDestinations: React.FC = React.memo(function RouteDestinations() {
const { getString } = useStrings() const { getString } = useStrings()
const repoPath = `${pathProps.space}/${pathProps.repoName}` const repoPath = `${pathProps.space}/${pathProps.repoName}`
const { OPEN_SOURCE_PIPELINES, OPEN_SOURCE_SECRETS } = useFeatureFlag() const { OPEN_SOURCE_PIPELINES, OPEN_SOURCE_SECRETS } = useFeatureFlag()
return ( return (

View File

@ -1,7 +1,7 @@
.container { .container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: black; background-color: var(--black);
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
} }
@ -14,7 +14,7 @@
.header { .header {
position: sticky; position: sticky;
top: 0; top: 0;
background-color: var(--black); background-color: var(--black) !important;
height: var(--log-content-header-height); height: var(--log-content-header-height);
.headerLayout { .headerLayout {

View File

@ -6,7 +6,7 @@ import type { CODEProps } from 'RouteDefinitions'
import type { TypesStage } from 'services/code' import type { TypesStage } from 'services/code'
import ConsoleStep from 'components/ConsoleStep/ConsoleStep' import ConsoleStep from 'components/ConsoleStep/ConsoleStep'
import { timeDistance } from 'utils/Utils' import { timeDistance } from 'utils/Utils'
// import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata' import { useStrings } from 'framework/strings'
import css from './Console.module.scss' import css from './Console.module.scss'
interface ConsoleProps { interface ConsoleProps {
@ -16,6 +16,7 @@ interface ConsoleProps {
const Console: FC<ConsoleProps> = ({ stage, repoPath }) => { const Console: FC<ConsoleProps> = ({ stage, repoPath }) => {
const { pipeline, execution: executionNum } = useParams<CODEProps>() const { pipeline, execution: executionNum } = useParams<CODEProps>()
const { getString } = useStrings()
return ( return (
<div className={css.container}> <div className={css.container}>
@ -26,8 +27,7 @@ const Console: FC<ConsoleProps> = ({ stage, repoPath }) => {
</Text> </Text>
{stage?.started && stage?.stopped && ( {stage?.started && stage?.stopped && (
<Text font={{ variation: FontVariation.BODY }} color={Color.GREY_500}> <Text font={{ variation: FontVariation.BODY }} color={Color.GREY_500}>
{/* this needs fixed */} {getString('executions.completedTime', { timeString: timeDistance(stage?.stopped, Date.now()) })}
{timeDistance(stage?.started, stage?.stopped)}
</Text> </Text>
)} )}
</Layout.Horizontal> </Layout.Horizontal>

View File

@ -1,9 +1,9 @@
.logLayout { .logLayout {
margin-left: var(--spacing-xxxlarge) !important; margin-left: 30px !important;
} }
.lineNumber { .lineNumber {
width: var(--spacing-xlarge); min-width: var(--spacing-xlarge);
color: #999; color: #999;
margin-right: 16px; margin-right: 16px;
font-family: 'Roboto Mono' !important; font-family: 'Roboto Mono' !important;

View File

@ -1,35 +1,22 @@
import { Layout, Text } from '@harnessio/uicore' import { FlexExpander, Layout, Text } from '@harnessio/uicore'
import React, { FC } from 'react' import React, { FC } from 'react'
import type { LivelogLine } from 'services/code'
import css from './ConsoleLogs.module.scss' import css from './ConsoleLogs.module.scss'
// currently a string - should be an array of strings in future
interface ConsoleLogsProps { interface ConsoleLogsProps {
logs: string logs: LivelogLine[]
}
interface log {
pos: number
out: string
time: number
}
const convertStringToLogArray = (logs: string): log[] => {
const logStrings = logs.split('\n').map(log => {
return JSON.parse(log)
})
return logStrings
} }
const ConsoleLogs: FC<ConsoleLogsProps> = ({ logs }) => { const ConsoleLogs: FC<ConsoleLogsProps> = ({ logs }) => {
const logArray = convertStringToLogArray(logs)
return ( return (
<> <>
{logArray.map((log, index) => { {logs.map((log, index) => {
return ( return (
<Layout.Horizontal key={index} spacing={'medium'} className={css.logLayout}> <Layout.Horizontal key={index} spacing={'medium'} className={css.logLayout}>
<Text className={css.lineNumber}>{log.pos}</Text> <Text className={css.lineNumber}>{log.pos}</Text>
<Text className={css.log}>{log.out}</Text> <Text className={css.log}>{log.out}</Text>
<FlexExpander />
<Text>{log.time}s</Text>
</Layout.Horizontal> </Layout.Horizontal>
) )
})} })}

View File

@ -7,3 +7,16 @@
.loading { .loading {
margin-left: var(--spacing-xxxlarge) !important; margin-left: var(--spacing-xxxlarge) !important;
} }
.spin {
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}

View File

@ -1,7 +1,8 @@
/* eslint-disable */ /* eslint-disable */
// this is an auto-generated file // this is an auto-generated file
declare const styles: { declare const styles: {
readonly stepLayout: string readonly spin: string
readonly loading: string readonly loading: string
readonly stepLayout: string
} }
export default styles export default styles

View File

@ -1,12 +1,13 @@
import { Icon } from '@harnessio/icons' import { Icon } from '@harnessio/icons'
import { FlexExpander, Layout } from '@harnessio/uicore' import { FlexExpander, Layout } from '@harnessio/uicore'
import React, { FC, useEffect } from 'react' import React, { FC, useEffect, useRef, useState } from 'react'
import { useGet } from 'restful-react' import { useGet } from 'restful-react'
import { Text } from '@harnessio/uicore' import { Text } from '@harnessio/uicore'
import type { TypesStep } from 'services/code' import type { LivelogLine, TypesStep } from 'services/code'
import { timeDistance } from 'utils/Utils' import { timeDistance } from 'utils/Utils'
import ConsoleLogs from 'components/ConsoleLogs/ConsoleLogs' import ConsoleLogs from 'components/ConsoleLogs/ConsoleLogs'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
import { ExecutionState } from 'components/ExecutionStatus/ExecutionStatus'
import css from './ConsoleStep.module.scss' import css from './ConsoleStep.module.scss'
interface ConsoleStepProps { interface ConsoleStepProps {
@ -20,20 +21,68 @@ interface ConsoleStepProps {
const ConsoleStep: FC<ConsoleStepProps> = ({ step, stageNumber, repoPath, pipelineName, executionNumber }) => { const ConsoleStep: FC<ConsoleStepProps> = ({ step, stageNumber, repoPath, pipelineName, executionNumber }) => {
const { getString } = useStrings() const { getString } = useStrings()
const [isOpened, setIsOpened] = React.useState(false) const [isOpened, setIsOpened] = useState(false)
const [streamingLogs, setStreamingLogs] = useState<LivelogLine[]>([])
const eventSourceRef = useRef<EventSource | null>(null)
const { data, error, loading, refetch } = useGet<string>({ const shouldUseGet = step?.status !== ExecutionState.RUNNING && step?.status !== ExecutionState.PENDING
const isPending = step?.status === ExecutionState.PENDING
const { data, error, loading, refetch } = useGet<LivelogLine[]>({
path: `/api/v1/repos/${repoPath}/+/pipelines/${pipelineName}/executions/${executionNumber}/logs/${String( path: `/api/v1/repos/${repoPath}/+/pipelines/${pipelineName}/executions/${executionNumber}/logs/${String(
stageNumber stageNumber
)}/${String(step?.number)}`, )}/${String(step?.number)}`,
lazy: true lazy: true
}) })
// this refetches any open steps when the stage number changes - really it shouldnt refetch until reopened...
useEffect(() => { useEffect(() => {
setIsOpened(false) setIsOpened(false)
refetch() }, [stageNumber])
}, [stageNumber, refetch])
useEffect(() => {
if (step?.status === ExecutionState.RUNNING) {
if (eventSourceRef.current) {
eventSourceRef.current.close()
setStreamingLogs([])
}
eventSourceRef.current = new EventSource(
`/api/v1/repos/${repoPath}/+/pipelines/${pipelineName}/executions/${executionNumber}/logs/${String(
stageNumber
)}/${String(step?.number)}/stream`
)
eventSourceRef.current.onmessage = event => {
const newLog = JSON.parse(event.data)
setStreamingLogs(existingLogs => {
return [...existingLogs, newLog]
})
}
}
return () => {
if (eventSourceRef.current) eventSourceRef.current.close()
}
}, [executionNumber, pipelineName, repoPath, stageNumber, step?.number, step?.status])
let icon
if (step?.status === ExecutionState.SUCCESS) {
icon = <Icon name="success-tick" />
} else if (isPending) {
icon = <Icon name="circle" />
} else if (step?.status === ExecutionState.RUNNING) {
icon = <Icon className={css.spin} name="pending" />
} else {
icon = <Icon name="circle" /> // Default icon in case of other statuses or unknown status
}
let content
if (loading) {
content = <div className={css.loading}>{getString('loading')}</div>
} else if (error && step?.status !== ExecutionState.RUNNING) {
content = <div>Error: {error.message}</div>
} else if (streamingLogs.length) {
content = <ConsoleLogs logs={streamingLogs} />
} else if (data) {
content = <ConsoleLogs logs={data} />
}
return ( return (
<> <>
@ -41,25 +90,20 @@ const ConsoleStep: FC<ConsoleStepProps> = ({ step, stageNumber, repoPath, pipeli
className={css.stepLayout} className={css.stepLayout}
spacing="medium" spacing="medium"
onClick={() => { onClick={() => {
setIsOpened(!isOpened) if (!isPending) {
if (!data && !loading) refetch() setIsOpened(!isOpened)
if (shouldUseGet && !isOpened) refetch()
}
}}> }}>
<Icon name={isOpened ? 'chevron-down' : 'chevron-right'} /> <Icon name={isOpened ? 'chevron-down' : 'chevron-right'} />
<Icon name={step?.status === 'Success' ? 'success-tick' : 'circle'} /> {/* TODO - flesh icon logic out */}
{icon}
<Text>{step?.name}</Text> <Text>{step?.name}</Text>
<FlexExpander /> <FlexExpander />
{step?.started && step?.stopped && <div>{timeDistance(step?.stopped, step?.started)}</div>} {step?.started && step?.stopped && <div>{timeDistance(step?.stopped, step?.started)}</div>}
</Layout.Horizontal> </Layout.Horizontal>
{isOpened ? ( {isOpened && content}
loading ? (
<div className={css.loading}>{getString('loading')}</div>
) : error ? (
<div>Error: {error}</div>
) : data ? (
<ConsoleLogs logs={data} />
) : null
) : null}
</> </>
) )
} }

View File

@ -143,7 +143,7 @@ export function getCommentLineInfo(
) { ) {
const isSideBySideView = viewStyle === ViewStyle.SIDE_BY_SIDE const isSideBySideView = viewStyle === ViewStyle.SIDE_BY_SIDE
const { left, lineNumber, filePath } = commentEntry const { left, lineNumber, filePath } = commentEntry
const filePathBody = contentDOM?.querySelector(`[data="${filePath}"`) const filePathBody = filePath ? contentDOM?.querySelector(`[data="${filePath}"`) : contentDOM
const diffBody = filePathBody?.querySelector( const diffBody = filePathBody?.querySelector(
`${isSideBySideView ? `.d2h-file-side-diff${left ? '.left' : '.right'} ` : ''}.d2h-diff-tbody` `${isSideBySideView ? `.d2h-file-side-diff${left ? '.left' : '.right'} ` : ''}.d2h-diff-tbody`

View File

@ -5,16 +5,6 @@
gap: var(--spacing-small) !important; gap: var(--spacing-small) !important;
} }
.header {
width: 100% !important;
gap: var(--spacing-small) !important;
a {
font-size: var(--font-size-small);
color: var(--primary-7);
}
}
.breadcrumb { .breadcrumb {
align-items: center; align-items: center;
@ -36,6 +26,8 @@
} }
.executionInfo { .executionInfo {
display: flex !important;
gap: var(--spacing-small) !important;
width: 100% !important; width: 100% !important;
align-items: center !important; align-items: center !important;
margin-left: 0 !important; margin-left: 0 !important;

View File

@ -1,5 +1,5 @@
import React, { Fragment } from 'react' import React, { Fragment } from 'react'
import { Layout, Text, PageHeader, Utils, Avatar, FlexExpander } from '@harnessio/uicore' import { Layout, Text, PageHeader, Utils, Avatar, FlexExpander, Container } from '@harnessio/uicore'
import { Icon } from '@harnessio/icons' import { Icon } from '@harnessio/icons'
import { Color } from '@harnessio/design-system' import { Color } from '@harnessio/design-system'
import { Link, useParams } from 'react-router-dom' import { Link, useParams } from 'react-router-dom'
@ -78,8 +78,7 @@ export function ExecutionPageHeader({
} }
content={ content={
executionInfo && ( executionInfo && (
// TODO - margin left not playing ball... why? <Container className={css.executionInfo}>
<Layout.Horizontal className={css.executionInfo} spacing="small" style={{ marginLeft: 0 }}>
<ExecutionStatus status={getStatus(executionInfo.status)} iconOnly noBackground iconSize={18} /> <ExecutionStatus status={getStatus(executionInfo.status)} iconOnly noBackground iconSize={18} />
<Text inline color={Color.GREY_800} font={{ size: 'small' }}> <Text inline color={Color.GREY_800} font={{ size: 'small' }}>
{executionInfo.message} {executionInfo.message}
@ -106,14 +105,13 @@ export function ExecutionPageHeader({
<Text inline color={Color.GREY_500} font={{ size: 'small' }}> <Text inline color={Color.GREY_500} font={{ size: 'small' }}>
{timeDistance(executionInfo.started, executionInfo.finished)} {timeDistance(executionInfo.started, executionInfo.finished)}
</Text> </Text>
</Layout.Horizontal> <PipeSeparator height={7} />
<Layout.Horizontal spacing={'small'} style={{ alignItems: 'center' }}>
<Calendar height={16} width={16} color={Utils.getRealCSSColor(Color.GREY_500)} /> <Calendar height={16} width={16} color={Utils.getRealCSSColor(Color.GREY_500)} />
<Text inline color={Color.GREY_500} font={{ size: 'small' }}> <Text inline color={Color.GREY_500} font={{ size: 'small' }}>
{timeDistance(executionInfo.finished, Date.now())} ago {timeDistance(executionInfo.finished, Date.now())} ago
</Text> </Text>
</Layout.Horizontal> </Layout.Horizontal>
</Layout.Horizontal> </Container>
) )
} }
/> />

View File

@ -32,7 +32,7 @@ const ExecutionStage: FC<ExecutionStageProps> = ({ stage, isSelected = false, se
status={getStatus(stage.status || ExecutionState.PENDING)} status={getStatus(stage.status || ExecutionState.PENDING)}
iconOnly iconOnly
noBackground noBackground
iconSize={16} iconSize={18}
className={css.statusIcon} className={css.statusIcon}
/> />
<Text className={css.uid} lineClamp={1}> <Text className={css.uid} lineClamp={1}>

View File

@ -38,7 +38,7 @@ export interface NewSecretModalButtonProps extends Omit<ButtonProps, 'onClick' |
modalTitle: string modalTitle: string
submitButtonTitle?: string submitButtonTitle?: string
cancelButtonTitle?: string cancelButtonTitle?: string
onSubmit: (data: TypesSecret) => void onSuccess: () => void
} }
export const NewSecretModalButton: React.FC<NewSecretModalButtonProps> = ({ export const NewSecretModalButton: React.FC<NewSecretModalButtonProps> = ({
@ -46,12 +46,12 @@ export const NewSecretModalButton: React.FC<NewSecretModalButtonProps> = ({
modalTitle, modalTitle,
submitButtonTitle, submitButtonTitle,
cancelButtonTitle, cancelButtonTitle,
onSubmit, onSuccess,
...props ...props
}) => { }) => {
const ModalComponent: React.FC = () => { const ModalComponent: React.FC = () => {
const { getString } = useStrings() const { getString } = useStrings()
const { showError } = useToaster() const { showError, showSuccess } = useToaster()
const { mutate: createSecret, loading } = useMutate<TypesSecret>({ const { mutate: createSecret, loading } = useMutate<TypesSecret>({
verb: 'POST', verb: 'POST',
@ -66,9 +66,10 @@ export const NewSecretModalButton: React.FC<NewSecretModalButtonProps> = ({
description: formData.description, description: formData.description,
uid: formData.name uid: formData.name
} }
const response = await createSecret(payload) await createSecret(payload)
hideModal() hideModal()
onSubmit(response) showSuccess(getString('secrets.createSuccess'))
onSuccess()
} catch (exception) { } catch (exception) {
showError(getErrorMessage(exception), 0, getString('secrets.failedToCreate')) showError(getErrorMessage(exception), 0, getString('secrets.failedToCreate'))
} }
@ -152,7 +153,7 @@ export const NewSecretModalButton: React.FC<NewSecretModalButtonProps> = ({
) )
} }
const [openModal, hideModal] = useModalHook(ModalComponent, [onSubmit]) const [openModal, hideModal] = useModalHook(ModalComponent, [onSuccess])
return <Button onClick={openModal} {...props} /> return <Button onClick={openModal} {...props} />
} }

View File

@ -170,6 +170,7 @@ export interface StringsMap {
enterUser: string enterUser: string
error: string error: string
error404Text: string error404Text: string
'executions.completedTime': string
'executions.description': string 'executions.description': string
'executions.name': string 'executions.name': string
'executions.newExecutionButton': string 'executions.newExecutionButton': string
@ -480,11 +481,16 @@ export interface StringsMap {
searchBranches: string searchBranches: string
secret: string secret: string
'secrets.createSecret': string 'secrets.createSecret': string
'secrets.createSuccess': string
'secrets.deleteSecret': string
'secrets.deleteSecretConfirm': string
'secrets.enterSecretName': string 'secrets.enterSecretName': string
'secrets.failedToCreate': string 'secrets.failedToCreate': string
'secrets.failedToDeleteSecret': string
'secrets.name': string 'secrets.name': string
'secrets.newSecretButton': string 'secrets.newSecretButton': string
'secrets.noData': string 'secrets.noData': string
'secrets.secretDeleted': string
'secrets.value': string 'secrets.value': string
selectBranchPlaceHolder: string selectBranchPlaceHolder: string
selectRange: string selectRange: string

View File

@ -648,6 +648,7 @@ executions:
name: Execution Name name: Execution Name
description: Description description: Description
time: Time time: Time
completedTime: completed {{timeString}} ago
selectRange: Shift-click to select a range selectRange: Shift-click to select a range
allCommits: All Commits allCommits: All Commits
secrets: secrets:
@ -658,6 +659,11 @@ secrets:
enterSecretName: Enter Secret name enterSecretName: Enter Secret name
value: Secret Value value: Secret Value
createSecret: Create Secret createSecret: Create Secret
createSuccess: Secret created successfully
secretDeleted: Secret {uid} deleted.
deleteSecretConfirm: Are you sure you want to delete secret <strong>{{uid}}</strong>? You can't undo this action.
failedToDeleteSecret: Failed to delete Secret. Please try again.
deleteSecret: Delete Secrets
userUpdateSuccess: 'User updated successfully' userUpdateSuccess: 'User updated successfully'
run: Run run: Run
plugins: plugins:

View File

@ -9,13 +9,14 @@ import {
PageBody, PageBody,
TableV2 as Table, TableV2 as Table,
Text, Text,
Utils Utils,
useToaster
} from '@harnessio/uicore' } from '@harnessio/uicore'
import { Color } from '@harnessio/design-system' import { Color } from '@harnessio/design-system'
import cx from 'classnames' import cx from 'classnames'
import type { CellProps, Column } from 'react-table' import type { CellProps, Column } from 'react-table'
import { Link, useHistory, useParams } from 'react-router-dom' import { Link, useHistory, useParams } from 'react-router-dom'
import { useGet } from 'restful-react' import { useGet, useMutate } from 'restful-react'
import { Timer, Calendar } from 'iconoir-react' import { Timer, Calendar } from 'iconoir-react'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner' import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
@ -29,7 +30,7 @@ import { usePageIndex } from 'hooks/usePageIndex'
import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination' import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination'
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata' import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
import { RepositoryPageHeader } from 'components/RepositoryPageHeader/RepositoryPageHeader' import { RepositoryPageHeader } from 'components/RepositoryPageHeader/RepositoryPageHeader'
import { ExecutionState, ExecutionStatus } from 'components/ExecutionStatus/ExecutionStatus' import { ExecutionStatus } from 'components/ExecutionStatus/ExecutionStatus'
import { getStatus } from 'utils/PipelineUtils' import { getStatus } from 'utils/PipelineUtils'
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator' import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
import noExecutionImage from '../RepositoriesListing/no-repo.svg' import noExecutionImage from '../RepositoriesListing/no-repo.svg'
@ -43,6 +44,7 @@ const ExecutionList = () => {
const pageBrowser = useQueryParams<PageBrowserProps>() const pageBrowser = useQueryParams<PageBrowserProps>()
const pageInit = pageBrowser.page ? parseInt(pageBrowser.page) : 1 const pageInit = pageBrowser.page ? parseInt(pageBrowser.page) : 1
const [page, setPage] = usePageIndex(pageInit) const [page, setPage] = usePageIndex(pageInit)
const { showError, showSuccess } = useToaster()
const { repoMetadata, error, loading, refetch } = useGetRepositoryMetadata() const { repoMetadata, error, loading, refetch } = useGetRepositoryMetadata()
@ -50,19 +52,39 @@ const ExecutionList = () => {
data: executions, data: executions,
error: executionsError, error: executionsError,
loading: executionsLoading, loading: executionsLoading,
response response,
refetch: executionsRefetch
} = useGet<TypesExecution[]>({ } = useGet<TypesExecution[]>({
path: `/api/v1/repos/${repoMetadata?.path}/+/pipelines/${pipeline}/executions`, path: `/api/v1/repos/${repoMetadata?.path}/+/pipelines/${pipeline}/executions`,
queryParams: { page, limit: LIST_FETCHING_LIMIT }, queryParams: { page, limit: LIST_FETCHING_LIMIT },
lazy: !repoMetadata lazy: !repoMetadata
}) })
//TODO - this should NOT be hardcoded to master branch - need a modal to insert branch
const { mutate, loading: mutateLoading } = useMutate<TypesExecution>({
verb: 'POST',
path: `/api/v1/repos/${repoMetadata?.path}/+/pipelines/${pipeline}/executions`,
queryParams: { branch: 'master' }
})
const handleClick = async () => {
try {
//TODO - really this should be handled by the event bus
await mutate(null)
showSuccess('Build started')
executionsRefetch()
} catch {
showError('Failed to start build')
}
}
const NewExecutionButton = ( const NewExecutionButton = (
<Button <Button
text={getString('executions.newExecutionButton')} text={getString('executions.newExecutionButton')}
variation={ButtonVariation.PRIMARY} variation={ButtonVariation.PRIMARY}
disabled={true} icon="play-outline"
icon="play-outline"></Button> disabled={mutateLoading}
onClick={handleClick}></Button>
) )
const columns: Column<TypesExecution>[] = useMemo( const columns: Column<TypesExecution>[] = useMemo(
@ -75,14 +97,9 @@ const ExecutionList = () => {
return ( return (
<Layout.Vertical className={css.nameContainer}> <Layout.Vertical className={css.nameContainer}>
<Layout.Horizontal spacing={'small'} style={{ alignItems: 'center' }}> <Layout.Horizontal spacing={'small'} style={{ alignItems: 'center' }}>
<ExecutionStatus <ExecutionStatus status={getStatus(record.status)} iconOnly noBackground iconSize={20} />
status={getStatus(record?.status || ExecutionState.PENDING)}
iconOnly
noBackground
iconSize={20}
/>
<Text className={css.number}>{`#${record.number}.`}</Text> <Text className={css.number}>{`#${record.number}.`}</Text>
<Text className={css.desc}>{record.title}</Text> <Text className={css.desc}>{record.message}</Text>
</Layout.Horizontal> </Layout.Horizontal>
<Layout.Horizontal spacing={'small'} style={{ alignItems: 'center', marginLeft: '1.2rem' }}> <Layout.Horizontal spacing={'small'} style={{ alignItems: 'center', marginLeft: '1.2rem' }}>
<Avatar email={record.author_email} name={record.author_name} size="small" hoverCard={false} /> <Avatar email={record.author_email} name={record.author_name} size="small" hoverCard={false} />
@ -112,16 +129,18 @@ const ExecutionList = () => {
const record = row.original const record = row.original
return ( return (
<Layout.Vertical spacing={'small'}> <Layout.Vertical spacing={'small'}>
<Layout.Horizontal spacing={'small'} style={{ alignItems: 'center' }}> {record?.started && record?.finished && (
<Timer color={Utils.getRealCSSColor(Color.GREY_500)} /> <Layout.Horizontal spacing={'small'} style={{ alignItems: 'center' }}>
<Text inline color={Color.GREY_500} lineClamp={1} width={180} font={{ size: 'small' }}> <Timer color={Utils.getRealCSSColor(Color.GREY_500)} />
{timeDistance(record.started, record.finished)} <Text inline color={Color.GREY_500} lineClamp={1} width={180} font={{ size: 'small' }}>
</Text> {timeDistance(record.started, record.finished)}
</Layout.Horizontal> </Text>
</Layout.Horizontal>
)}
<Layout.Horizontal spacing={'small'} style={{ alignItems: 'center' }}> <Layout.Horizontal spacing={'small'} style={{ alignItems: 'center' }}>
<Calendar color={Utils.getRealCSSColor(Color.GREY_500)} /> <Calendar color={Utils.getRealCSSColor(Color.GREY_500)} />
<Text inline color={Color.GREY_500} lineClamp={1} width={180} font={{ size: 'small' }}> <Text inline color={Color.GREY_500} lineClamp={1} width={180} font={{ size: 'small' }}>
{timeDistance(record.finished, Date.now())} ago {timeDistance(record.created, Date.now())} ago
</Text> </Text>
</Layout.Horizontal> </Layout.Horizontal>
</Layout.Vertical> </Layout.Vertical>

View File

@ -1,11 +1,9 @@
import React from 'react' import React from 'react'
import { ButtonVariation, Container, Layout, PageBody, Text } from '@harnessio/uicore' import { ButtonVariation, Container, Layout, PageBody, Text } from '@harnessio/uicore'
import { FontVariation } from '@harnessio/design-system' import { FontVariation } from '@harnessio/design-system'
import { useGet } from 'restful-react' import { noop } from 'lodash-es'
import { useHistory } from 'react-router-dom' import { useHistory } from 'react-router-dom'
// import type { TypesSpace } from 'services/code'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
// import { usePageIndex } from 'hooks/usePageIndex'
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner' import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
import { useAppContext } from 'AppContext' import { useAppContext } from 'AppContext'
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata' import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
@ -16,15 +14,11 @@ export default function Home() {
const { getString } = useStrings() const { getString } = useStrings()
const history = useHistory() const history = useHistory()
const { routes } = useAppContext() const { routes } = useAppContext()
// const [searchTerm, setSearchTerm] = useState('')
// const [page, setPage] = usePageIndex(1)
const { currentUser } = useAppContext() const { currentUser } = useAppContext()
const { space } = useGetRepositoryMetadata() const { space } = useGetRepositoryMetadata()
const spaces = [] const spaces = []
const { refetch } = useGet({
path: '/api/v1/user/memberships'
})
const NewSpaceButton = ( const NewSpaceButton = (
<NewSpaceModalButton <NewSpaceModalButton
space={space} space={space}
@ -34,7 +28,7 @@ export default function Home() {
icon="plus" icon="plus"
width={173} width={173}
height={48} height={48}
onRefetch={refetch} onRefetch={noop}
handleNavigation={spaceName => { handleNavigation={spaceName => {
history.push(routes.toCODERepositories({ space: spaceName })) history.push(routes.toCODERepositories({ space: spaceName }))
}} }}

View File

@ -31,6 +31,7 @@ import { useAppContext } from 'AppContext'
import { LatestCommitForFile } from 'components/LatestCommit/LatestCommit' import { LatestCommitForFile } from 'components/LatestCommit/LatestCommit'
import { useCommitModal } from 'components/CommitModalButton/CommitModalButton' import { useCommitModal } from 'components/CommitModalButton/CommitModalButton'
import { useStrings } from 'framework/strings' import { useStrings } from 'framework/strings'
import { getConfig } from 'services/config'
import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton' import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton'
import { PlainButton } from 'components/PlainButton/PlainButton' import { PlainButton } from 'components/PlainButton/PlainButton'
import { CommitsView } from 'components/CommitsView/CommitsView' import { CommitsView } from 'components/CommitsView/CommitsView'
@ -57,7 +58,6 @@ export function FileContent({
useFileContentViewerDecision({ repoMetadata, gitRef, resourcePath, resourceContent }) useFileContentViewerDecision({ repoMetadata, gitRef, resourcePath, resourceContent })
const history = useHistory() const history = useHistory()
const [activeTab, setActiveTab] = React.useState<string>(FileSection.CONTENT) const [activeTab, setActiveTab] = React.useState<string>(FileSection.CONTENT)
const content = useMemo( const content = useMemo(
() => decodeGitContent((resourceContent?.content as RepoFileContent)?.data), () => decodeGitContent((resourceContent?.content as RepoFileContent)?.data),
[resourceContent?.content] [resourceContent?.content]
@ -199,13 +199,18 @@ export function FileContent({
style={{ padding: '5px' }} style={{ padding: '5px' }}
width="145px" width="145px"
items={[ items={[
// { {
// hasIcon: true, hasIcon: true,
// iconName: 'arrow-right', iconName: 'arrow-right',
// text: getString('viewRaw'), text: getString('viewRaw'),
// onClick: () => window.open(rawURL, '_blank') // TODO: This is still not working due to token is not stored in cookies onClick: () => {
// }, const url = standalone
// '-', ? rawURL.replace(/^\/code/, '')
: getConfig(rawURL).replace('//', '/')
window.open(url, '_blank')
}
},
'-',
{ {
hasIcon: true, hasIcon: true,
iconName: 'cloud-download', iconName: 'cloud-download',
@ -243,6 +248,7 @@ export function FileContent({
<Match expr={isViewable}> <Match expr={isViewable}>
<Falsy> <Falsy>
<Center> <Center>
rawURL: {rawURL}
<Link <Link
to={rawURL} // TODO: Link component generates wrong copy link to={rawURL} // TODO: Link component generates wrong copy link
onClick={e => { onClick={e => {

View File

@ -1,45 +1,42 @@
@import 'src/utils/utils'; @import 'src/utils/utils';
.main { .main {
flex-grow: 1; --code-editor-border-color: var(--grey-200);
:global { .codeViewer {
.cm-editor { flex-grow: 1;
border: none !important;
.cm-scroller { :global {
padding: 0 !important; .cm-gutter {
background-color: var(--grey-50);
} }
.cm-content { .cm-editor {
padding: 0; border: none !important;
}
.cm-line { .cm-scroller {
&, padding: 0 !important;
* {
@include mono-font; .cm-line {
&,
* {
@include mono-font;
}
}
}
.cm-content {
padding: 0;
} }
} }
} }
}
.lineNo { .lineNo {
min-width: 70px !important; min-width: 70px !important;
text-align: right; text-align: right;
padding-right: 10px; padding-right: 10px;
height: 100%; height: 100%;
color: var(--grey-400); color: var(--grey-400);
}
}
.gitBlame {
--code-editor-border-color: var(--grey-200);
// padding: 0 var(--spacing-xlarge) 0 var(--spacing-small) !important;
:global {
.cm-gutter {
background-color: var(--grey-50);
} }
} }

View File

@ -148,7 +148,7 @@ export const GitBlame: React.FC<Pick<GitInfoProps, 'repoMetadata' | 'resourcePat
} }
return ( return (
<Container className={css.gitBlame}> <Container className={css.main}>
<Layout.Horizontal className={css.layout}> <Layout.Horizontal className={css.layout}>
<Container className={css.blameColumn}> <Container className={css.blameColumn}>
{Object.values(blameBlocks).map(blameInfo => ( {Object.values(blameBlocks).map(blameInfo => (
@ -246,7 +246,7 @@ const GitBlameRenderer = React.memo(function GitBlameSourceViewer({
filename={filename} filename={filename}
content={source} content={source}
readonly={true} readonly={true}
className={css.main} className={css.codeViewer}
onViewUpdate={onViewUpdate} onViewUpdate={onViewUpdate}
extensions={extensions.of([])} extensions={extensions.of([])}
maxHeight="auto" maxHeight="auto"

View File

@ -6,16 +6,17 @@ import {
Layout, Layout,
PageBody, PageBody,
PageHeader, PageHeader,
StringSubstitute,
TableV2 as Table, TableV2 as Table,
Text Text,
useToaster
} from '@harnessio/uicore' } from '@harnessio/uicore'
import { Color } from '@harnessio/design-system' import { Color, Intent } from '@harnessio/design-system'
import cx from 'classnames' import cx from 'classnames'
import type { CellProps, Column } from 'react-table' import type { CellProps, Column } from 'react-table'
import Keywords from 'react-keywords' import Keywords from 'react-keywords'
import { useHistory } from 'react-router-dom' import { useGet, useMutate } from 'restful-react'
import { useGet } from 'restful-react' import { String, useStrings } from 'framework/strings'
import { useStrings } from 'framework/strings'
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner' import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
import { SearchInputWithSpinner } from 'components/SearchInputWithSpinner/SearchInputWithSpinner' import { SearchInputWithSpinner } from 'components/SearchInputWithSpinner/SearchInputWithSpinner'
import { NoResultCard } from 'components/NoResultCard/NoResultCard' import { NoResultCard } from 'components/NoResultCard/NoResultCard'
@ -26,14 +27,13 @@ import { useQueryParams } from 'hooks/useQueryParams'
import { useGetSpaceParam } from 'hooks/useGetSpaceParam' import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination' import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination'
import { NewSecretModalButton } from 'components/NewSecretModalButton/NewSecretModalButton' import { NewSecretModalButton } from 'components/NewSecretModalButton/NewSecretModalButton'
import { useAppContext } from 'AppContext' import { useConfirmAct } from 'hooks/useConfirmAction'
import { OptionsMenuButton } from 'components/OptionsMenuButton/OptionsMenuButton'
import noSecretsImage from '../RepositoriesListing/no-repo.svg' import noSecretsImage from '../RepositoriesListing/no-repo.svg'
import css from './SecretList.module.scss' import css from './SecretList.module.scss'
const SecretList = () => { const SecretList = () => {
const { routes } = useAppContext()
const space = useGetSpaceParam() const space = useGetSpaceParam()
const history = useHistory()
const { getString } = useStrings() const { getString } = useStrings()
const [searchTerm, setSearchTerm] = useState<string | undefined>() const [searchTerm, setSearchTerm] = useState<string | undefined>()
const pageBrowser = useQueryParams<PageBrowserProps>() const pageBrowser = useQueryParams<PageBrowserProps>()
@ -58,9 +58,7 @@ const SecretList = () => {
text={getString('secrets.newSecretButton')} text={getString('secrets.newSecretButton')}
variation={ButtonVariation.PRIMARY} variation={ButtonVariation.PRIMARY}
icon="plus" icon="plus"
onSubmit={secretInfo => onSuccess={() => refetch()}></NewSecretModalButton>
history.push(routes.toCODESecret({ space, secret: secretInfo.uid as string }))
}></NewSecretModalButton>
) )
const columns: Column<TypesSecret>[] = useMemo( const columns: Column<TypesSecret>[] = useMemo(
@ -97,9 +95,62 @@ const SecretList = () => {
) )
}, },
disableSortBy: true disableSortBy: true
},
{
id: 'action',
width: '30px',
Cell: ({ row }: CellProps<TypesSecret>) => {
const { mutate: deleteSecret } = useMutate({
verb: 'DELETE',
path: `/api/v1/secrets/${space}/${row.original.uid}`
})
const { showSuccess, showError } = useToaster()
const confirmDeleteSecret = useConfirmAct()
// TODO - add edit option
return (
<OptionsMenuButton
isDark
width="100px"
items={[
{
text: getString('delete'),
isDanger: true,
onClick: () =>
confirmDeleteSecret({
title: getString('secrets.deleteSecret'),
confirmText: getString('delete'),
intent: Intent.DANGER,
message: (
<String useRichText stringID="secrets.deleteSecretConfirm" vars={{ uid: row.original.uid }} />
),
action: async () => {
deleteSecret({})
.then(() => {
showSuccess(
<StringSubstitute
str={getString('secrets.secretDeleted')}
vars={{
uid: row.original.uid
}}
/>,
5000
)
refetch()
})
.catch(secretDeleteError => {
showError(getErrorMessage(secretDeleteError), 0, 'secrets.failedToDeleteSecret')
})
}
})
}
]}
/>
)
}
} }
], ],
[getString, searchTerm] [getString, refetch, searchTerm, space]
) )
return ( return (
@ -130,9 +181,6 @@ const SecretList = () => {
className={css.table} className={css.table}
columns={columns} columns={columns}
data={secrets || []} data={secrets || []}
onRowClick={secretInfo =>
history.push(routes.toCODESecret({ space: 'root', secret: secretInfo.uid as string }))
}
getRowClassName={row => cx(css.row, !row.original.description && css.noDesc)} getRowClassName={row => cx(css.row, !row.original.description && css.noDesc)}
/> />
)} )}

View File

@ -286,7 +286,7 @@ export default function Webhooks() {
showWhen={() => webhooks?.length === 0} showWhen={() => webhooks?.length === 0}
forSearch={!!searchTerm} forSearch={!!searchTerm}
message={getString('webhookEmpty')} message={getString('webhookEmpty')}
buttonText={getString('createWebhook')} buttonText={getString('newWebhook')}
onButtonClick={() => onButtonClick={() =>
history.push( history.push(
routes.toCODEWebhookNew({ routes.toCODEWebhookNew({

View File

@ -740,6 +740,7 @@ export interface TypesRepository {
fork_id?: number fork_id?: number
git_url?: string git_url?: string
id?: number id?: number
importing?: boolean
is_public?: boolean is_public?: boolean
num_closed_pulls?: number num_closed_pulls?: number
num_forks?: number num_forks?: number

View File

@ -7453,6 +7453,8 @@ components:
type: string type: string
id: id:
type: integer type: integer
importing:
type: boolean
is_public: is_public:
type: boolean type: boolean
num_closed_pulls: num_closed_pulls:

View File

@ -1,6 +1,6 @@
import { ExecutionState } from 'components/ExecutionStatus/ExecutionStatus' import { ExecutionState } from 'components/ExecutionStatus/ExecutionStatus'
export const getStatus = (status: string): ExecutionState => { export const getStatus = (status: string | undefined): ExecutionState => {
switch (status) { switch (status) {
case 'success': case 'success':
return ExecutionState.SUCCESS return ExecutionState.SUCCESS
@ -10,6 +10,8 @@ export const getStatus = (status: string): ExecutionState => {
return ExecutionState.RUNNING return ExecutionState.RUNNING
case 'pending': case 'pending':
return ExecutionState.PENDING return ExecutionState.PENDING
case 'error':
return ExecutionState.ERROR
default: default:
return ExecutionState.PENDING return ExecutionState.PENDING
} }

View File

@ -2,9 +2,11 @@ $code-editor-font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menl
monospace; monospace;
@mixin mono-font { @mixin mono-font {
font-family: var(--font-family-mono) !important; font-family: Menlo, Monaco, 'Courier New', monospace var(--font-family-mono) !important;
font-weight: normal !important;
font-size: 13px !important; font-size: 13px !important;
font-feature-settings: 'liga' 0, 'calt' 0; font-feature-settings: 'liga' 0, 'calt' 0;
font-variation-settings: normal;
line-height: 18px; line-height: 18px;
letter-spacing: 0px; letter-spacing: 0px;
} }

View File

@ -2219,14 +2219,6 @@ agent-base@6:
dependencies: dependencies:
debug "4" debug "4"
aggregate-error@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
dependencies:
clean-stack "^2.0.0"
indent-string "^4.0.0"
ajv-formats@^2.1.1: ajv-formats@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
@ -2293,7 +2285,7 @@ ansi-colors@^4.1.1:
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b"
integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==
ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: ansi-escapes@^4.2.1:
version "4.3.2" version "4.3.2"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
@ -2994,11 +2986,6 @@ clean-css@^5.2.2:
dependencies: dependencies:
source-map "~0.6.0" source-map "~0.6.0"
clean-stack@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
cli-boxes@^1.0.0: cli-boxes@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
@ -3011,14 +2998,6 @@ cli-cursor@^3.1.0:
dependencies: dependencies:
restore-cursor "^3.1.0" restore-cursor "^3.1.0"
cli-truncate@2.1.0, cli-truncate@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7"
integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==
dependencies:
slice-ansi "^3.0.0"
string-width "^4.2.0"
cli-width@^3.0.0: cli-width@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
@ -3127,12 +3106,7 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colorette@^1.4.0: colorette@^2.0.10, colorette@^2.0.14:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40"
integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==
colorette@^2.0.10, colorette@^2.0.14, colorette@^2.0.16:
version "2.0.20" version "2.0.20"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
@ -3174,7 +3148,7 @@ commander@^4.1.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
commander@^8.2.0, commander@^8.3.0: commander@^8.3.0:
version "8.3.0" version "8.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
@ -3289,17 +3263,6 @@ cosmiconfig@^6.0.0:
path-type "^4.0.0" path-type "^4.0.0"
yaml "^1.7.2" yaml "^1.7.2"
cosmiconfig@^7.0.1:
version "7.1.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
dependencies:
"@types/parse-json" "^4.0.0"
import-fresh "^3.2.1"
parse-json "^5.0.0"
path-type "^4.0.0"
yaml "^1.10.0"
create-error-class@^3.0.0: create-error-class@^3.0.0:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
@ -3436,7 +3399,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
dependencies: dependencies:
ms "2.0.0" ms "2.0.0"
debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4:
version "4.3.4" version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -3826,7 +3789,7 @@ enhanced-resolve@^5.0.0, enhanced-resolve@^5.13.0, enhanced-resolve@^5.7.0:
graceful-fs "^4.2.4" graceful-fs "^4.2.4"
tapable "^2.2.0" tapable "^2.2.0"
enquirer@^2.3.5, enquirer@^2.3.6: enquirer@^2.3.5:
version "2.3.6" version "2.3.6"
resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
@ -4260,7 +4223,7 @@ execa@^4.0.0:
signal-exit "^3.0.2" signal-exit "^3.0.2"
strip-final-newline "^2.0.0" strip-final-newline "^2.0.0"
execa@^5.0.0, execa@^5.1.1: execa@^5.0.0:
version "5.1.1" version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
@ -4745,11 +4708,6 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@
has "^1.0.3" has "^1.0.3"
has-symbols "^1.0.3" has-symbols "^1.0.3"
get-own-enumerable-property-symbols@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
get-package-type@^0.1.0: get-package-type@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
@ -5811,7 +5769,7 @@ is-number@^7.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-obj@^1.0.0, is-obj@^1.0.1: is-obj@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg== integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==
@ -5858,11 +5816,6 @@ is-regex@^1.0.4, is-regex@^1.1.4:
call-bind "^1.0.2" call-bind "^1.0.2"
has-tostringtag "^1.0.0" has-tostringtag "^1.0.0"
is-regexp@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==
is-retry-allowed@^1.0.0: is-retry-allowed@^1.0.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
@ -6756,40 +6709,6 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
lint-staged@^11.0.0:
version "11.2.6"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.2.6.tgz#f477b1af0294db054e5937f171679df63baa4c43"
integrity sha512-Vti55pUnpvPE0J9936lKl0ngVeTdSZpEdTNhASbkaWX7J5R9OEifo1INBGQuGW4zmy6OG+TcWPJ3m5yuy5Q8Tg==
dependencies:
cli-truncate "2.1.0"
colorette "^1.4.0"
commander "^8.2.0"
cosmiconfig "^7.0.1"
debug "^4.3.2"
enquirer "^2.3.6"
execa "^5.1.1"
listr2 "^3.12.2"
micromatch "^4.0.4"
normalize-path "^3.0.0"
please-upgrade-node "^3.2.0"
string-argv "0.3.1"
stringify-object "3.3.0"
supports-color "8.1.1"
listr2@^3.12.2:
version "3.14.0"
resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e"
integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==
dependencies:
cli-truncate "^2.1.0"
colorette "^2.0.16"
log-update "^4.0.0"
p-map "^4.0.0"
rfdc "^1.3.0"
rxjs "^7.5.1"
through "^2.3.8"
wrap-ansi "^7.0.0"
load-json-file@^4.0.0: load-json-file@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@ -6858,16 +6777,6 @@ lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21,
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-update@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==
dependencies:
ansi-escapes "^4.3.0"
cli-cursor "^3.1.0"
slice-ansi "^4.0.0"
wrap-ansi "^6.2.0"
longest-streak@^3.0.0: longest-streak@^3.0.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4"
@ -7573,10 +7482,10 @@ monaco-editor-webpack-plugin@^7.0.1:
dependencies: dependencies:
loader-utils "^2.0.2" loader-utils "^2.0.2"
monaco-editor@^0.37.1: monaco-editor@^0.40.0:
version "0.37.1" version "0.40.0"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.37.1.tgz#d6f5ffb593e019e74e19bf8a2bdef5a691876f4e" resolved "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.40.0.tgz#d10834e15ad50a15ec61fd01892e508464ebe2fe"
integrity sha512-jLXEEYSbqMkT/FuJLBZAVWGuhIb4JNwHE9kPTorAVmsdZ4UzHAfgWxLsVtD7pLRFaOwYPhNG9nUCpmFL1t/dIg== integrity sha512-1wymccLEuFSMBvCk/jT1YDW/GuxMLYwnFwF9CDyYCxoTw2Pt379J3FUhwy9c43j51JdcxVPjwk0jm0EVDsBS2g==
monaco-marker-data-provider@^1.0.0: monaco-marker-data-provider@^1.0.0:
version "1.1.1" version "1.1.1"
@ -8107,13 +8016,6 @@ p-locate@^4.1.0:
dependencies: dependencies:
p-limit "^2.2.0" p-limit "^2.2.0"
p-map@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
dependencies:
aggregate-error "^3.0.0"
p-retry@^4.5.0: p-retry@^4.5.0:
version "4.6.2" version "4.6.2"
resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16"
@ -8345,13 +8247,6 @@ pkg-dir@^4.2.0:
dependencies: dependencies:
find-up "^4.0.0" find-up "^4.0.0"
please-upgrade-node@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==
dependencies:
semver-compare "^1.0.0"
popper.js@^1.14.4, popper.js@^1.15.0: popper.js@^1.14.4, popper.js@^1.15.0:
version "1.16.1" version "1.16.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
@ -8708,13 +8603,20 @@ react-markdown@~8.0.0:
unist-util-visit "^4.0.0" unist-util-visit "^4.0.0"
vfile "^5.0.0" vfile "^5.0.0"
react-monaco-editor@*, react-monaco-editor@^0.52.0: react-monaco-editor@*:
version "0.52.0" version "0.52.0"
resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.52.0.tgz#69a7c450a22830064d2fc1b446674b1b7da0f540" resolved "https://registry.yarnpkg.com/react-monaco-editor/-/react-monaco-editor-0.52.0.tgz#69a7c450a22830064d2fc1b446674b1b7da0f540"
integrity sha512-jhQSekf2JABbcpN45gKZlWfTS0QcBOZAbAWKGyfqy/KEcMXTwJpCOYGcn2Ur11SUUxWJUzhKjE2fx9BGBc5S8g== integrity sha512-jhQSekf2JABbcpN45gKZlWfTS0QcBOZAbAWKGyfqy/KEcMXTwJpCOYGcn2Ur11SUUxWJUzhKjE2fx9BGBc5S8g==
dependencies: dependencies:
prop-types "^15.8.1" prop-types "^15.8.1"
react-monaco-editor@^0.54.0:
version "0.54.0"
resolved "https://registry.npmjs.org/react-monaco-editor/-/react-monaco-editor-0.54.0.tgz#ec9293249a991b08264be723c1ec0ca3a6d480d8"
integrity sha512-9JwO69851mfpuhYLHlKbae7omQWJ/2ICE2lbL0VHyNyZR8rCOH7440u+zAtDgiOMpLwmYdY1sEZCdRefywX6GQ==
dependencies:
prop-types "^15.8.1"
react-pdf@^7.1.2: react-pdf@^7.1.2:
version "7.1.2" version "7.1.2"
resolved "https://registry.yarnpkg.com/react-pdf/-/react-pdf-7.1.2.tgz#c6979cff9ac09c3e5ab7ea9e0182f79a499768e5" resolved "https://registry.yarnpkg.com/react-pdf/-/react-pdf-7.1.2.tgz#c6979cff9ac09c3e5ab7ea9e0182f79a499768e5"
@ -9291,11 +9193,6 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rfdc@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
rimraf@^3.0.0, rimraf@^3.0.2: rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@ -9327,13 +9224,6 @@ rxjs@^6.6.0:
dependencies: dependencies:
tslib "^1.9.0" tslib "^1.9.0"
rxjs@^7.5.1:
version "7.8.0"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.0.tgz#90a938862a82888ff4c7359811a595e14e1e09a4"
integrity sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==
dependencies:
tslib "^2.1.0"
sade@^1.7.3: sade@^1.7.3:
version "1.8.1" version "1.8.1"
resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701"
@ -9459,11 +9349,6 @@ selfsigned@^2.1.1:
dependencies: dependencies:
node-forge "^1" node-forge "^1"
semver-compare@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==
semver-diff@^2.0.0: semver-diff@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
@ -9676,15 +9561,6 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
slice-ansi@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==
dependencies:
ansi-styles "^4.0.0"
astral-regex "^2.0.0"
is-fullwidth-code-point "^3.0.0"
slice-ansi@^4.0.0: slice-ansi@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
@ -9890,11 +9766,6 @@ stop-iteration-iterator@^1.0.0:
dependencies: dependencies:
internal-slot "^1.0.4" internal-slot "^1.0.4"
string-argv@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"
integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==
string-length@^4.0.1: string-length@^4.0.1:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
@ -9993,15 +9864,6 @@ string_decoder@~1.1.1:
dependencies: dependencies:
safe-buffer "~5.1.0" safe-buffer "~5.1.0"
stringify-object@3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
dependencies:
get-own-enumerable-property-symbols "^3.0.0"
is-obj "^1.0.1"
is-regexp "^1.0.0"
strip-ansi@^3.0.0, strip-ansi@^3.0.1: strip-ansi@^3.0.0, strip-ansi@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
@ -10077,13 +9939,6 @@ style-to-object@^0.4.0:
dependencies: dependencies:
inline-style-parser "0.1.1" inline-style-parser "0.1.1"
supports-color@8.1.1, supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-color@^5.3.0: supports-color@^5.3.0:
version "5.5.0" version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@ -10098,6 +9953,13 @@ supports-color@^7.0.0, supports-color@^7.1.0:
dependencies: dependencies:
has-flag "^4.0.0" has-flag "^4.0.0"
supports-color@^8.0.0:
version "8.1.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
dependencies:
has-flag "^4.0.0"
supports-hyperlinks@^2.0.0: supports-hyperlinks@^2.0.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624"
@ -10214,7 +10076,7 @@ throat@^5.0.0:
resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
through@^2.3.6, through@^2.3.8: through@^2.3.6:
version "2.3.8" version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==