diff --git a/cmd/builder/builder.go b/cmd/builder/builder.go index 0708a192..40316e67 100644 --- a/cmd/builder/builder.go +++ b/cmd/builder/builder.go @@ -139,31 +139,31 @@ func (b Builder) gitClone() error { return fmt.Errorf("git not found: %v", err) } cmd := exec.Command(git, "clone", "--branch", ptr.To(b.ScmBranch)) - if b.ScmDepth != 0 { - cmd.Args = append(cmd.Args, "--depth", strconv.Itoa(b.ScmDepth)) + if ptr.To(b.ScmDepth) != 0 { + cmd.Args = append(cmd.Args, "--depth", strconv.Itoa(ptr.To(b.ScmDepth))) } - if b.ScmSubmodule { + if ptr.To(b.ScmSubmodule) { cmd.Args = append(cmd.Args, "--recurse-submodules") } - if b.ScmCredentialType == enums.ScmCredentialTypeSsh { + if ptr.To(b.ScmCredentialType) == enums.ScmCredentialTypeSsh { cmd.Args = append(cmd.Args, "-i", path.Join(homeSigma, privateKey)) cmd.Env = append(os.Environ(), fmt.Sprintf("SSH_KNOWN_HOSTS=%s", path.Join(homeSigma, knownHosts))) } - repository := b.ScmRepository - if b.ScmCredentialType == enums.ScmCredentialTypeToken { + repository := ptr.To(b.ScmRepository) + if ptr.To(b.ScmCredentialType) == enums.ScmCredentialTypeToken { u, err := url.Parse(repository) if err != nil { return fmt.Errorf("SCM_REPOSITORY parse with url failed: %v", err) } - repository = fmt.Sprintf("%s//%s@%s/%s", u.Scheme, b.ScmToken, u.Host, u.Path) + repository = fmt.Sprintf("%s//%s@%s/%s", u.Scheme, ptr.To(b.ScmToken), u.Host, u.Path) } - if b.ScmCredentialType == enums.ScmCredentialTypeUsername { + if ptr.To(b.ScmCredentialType) == enums.ScmCredentialTypeUsername { endpoint, err := transport.NewEndpoint(repository) if err != nil { return fmt.Errorf("transport.NewEndpoint failed: %v", err) } - endpoint.User = b.ScmUsername - endpoint.Password = b.ScmPassword + endpoint.User = ptr.To(b.ScmUsername) + endpoint.Password = ptr.To(b.ScmPassword) repository = endpoint.String() } cmd.Args = append(cmd.Args, repository, workspace) diff --git a/cmd/builder/checker.go b/cmd/builder/checker.go index 3c09b859..97215d7a 100644 --- a/cmd/builder/checker.go +++ b/cmd/builder/checker.go @@ -20,6 +20,7 @@ import ( "github.com/go-sigma/sigma/pkg/types/enums" "github.com/go-sigma/sigma/pkg/utils/crypt" + "github.com/go-sigma/sigma/pkg/utils/ptr" ) func (b *Builder) checker() error { @@ -29,37 +30,41 @@ func (b *Builder) checker() error { return fmt.Errorf("SCM_CREDENTIAL_TYPE should be one of 'ssh', 'token' or 'none', but got '%s'", b.ScmCredentialType.String()) } - if b.ScmCredentialType == enums.ScmCredentialTypeSsh && b.ScmSshKey == "" { + if b.ScmCredentialType != nil && ptr.To(b.ScmCredentialType) == enums.ScmCredentialTypeSsh && ptr.To(b.ScmSshKey) == "" { return fmt.Errorf("SCM_SSH_KEY should be set, if SCM_CREDENTIAL_TYPE is 'ssh'") } - if b.ScmSshKey != "" { - b.ScmSshKey, err = crypt.Decrypt(fmt.Sprintf("%d-%d", b.BuilderID, b.RunnerID), b.ScmSshKey) + if ptr.To(b.ScmSshKey) != "" { + scmSshKey, err := crypt.Decrypt(fmt.Sprintf("%d-%d", b.BuilderID, b.RunnerID), ptr.To(b.ScmSshKey)) if err != nil { return fmt.Errorf("Decrypt ssh key failed: %v", err) } + b.ScmSshKey = ptr.Of(scmSshKey) } - if b.ScmCredentialType == enums.ScmCredentialTypeToken && b.ScmToken == "" { + if b.ScmCredentialType != nil && ptr.To(b.ScmCredentialType) == enums.ScmCredentialTypeToken && ptr.To(b.ScmToken) == "" { return fmt.Errorf("SCM_TOKEN should be set, if SCM_CREDENTIAL_TYPE is 'token'") } - if b.ScmToken != "" { - b.ScmToken, err = crypt.Decrypt(fmt.Sprintf("%d-%d", b.BuilderID, b.RunnerID), b.ScmToken) + if ptr.To(b.ScmToken) != "" { + scmToken, err := crypt.Decrypt(fmt.Sprintf("%d-%d", b.BuilderID, b.RunnerID), ptr.To(b.ScmToken)) if err != nil { return fmt.Errorf("Decrypt scm token failed: %v", err) } + b.ScmToken = ptr.Of(scmToken) } - if b.ScmCredentialType == enums.ScmCredentialTypeToken && (!strings.HasPrefix(b.ScmRepository, "http://") && !strings.HasPrefix(b.ScmRepository, "https://")) { + if b.ScmCredentialType != nil && ptr.To(b.ScmCredentialType) == enums.ScmCredentialTypeToken && + (!strings.HasPrefix(ptr.To(b.ScmRepository), "http://") && !strings.HasPrefix(ptr.To(b.ScmRepository), "https://")) { return fmt.Errorf("SCM_REPOSITORY should be started with 'http://' or 'https://', if SCM_CREDENTIAL_TYPE is 'token'") } - if b.ScmCredentialType == enums.ScmCredentialTypeUsername && (b.ScmUsername == "" || b.ScmPassword == "") { + if b.ScmCredentialType != nil && ptr.To(b.ScmCredentialType) == enums.ScmCredentialTypeUsername && (ptr.To(b.ScmUsername) == "" || ptr.To(b.ScmPassword) == "") { return fmt.Errorf("SCM_USERNAME and SCM_PASSWORD should be set, if SCM_CREDENTIAL_TYPE is 'username'") } - if b.ScmPassword != "" { - b.ScmPassword, err = crypt.Decrypt(fmt.Sprintf("%d-%d", b.BuilderID, b.RunnerID), b.ScmPassword) + if ptr.To(b.ScmPassword) != "" { + scmPassword, err := crypt.Decrypt(fmt.Sprintf("%d-%d", b.BuilderID, b.RunnerID), ptr.To(b.ScmPassword)) if err != nil { return fmt.Errorf("Decrypt scm password failed: %v", err) } + b.ScmPassword = ptr.Of(scmPassword) } if !b.ScmProvider.IsValid() { diff --git a/cmd/builder/init.go b/cmd/builder/init.go index ffa49bed..0eec0784 100644 --- a/cmd/builder/init.go +++ b/cmd/builder/init.go @@ -37,12 +37,12 @@ import ( // initToken init git clone token and buildkit push token func (b Builder) initToken() error { - if b.ScmCredentialType == enums.ScmCredentialTypeSsh { + if b.ScmCredentialType != nil && ptr.To(b.ScmCredentialType) == enums.ScmCredentialTypeSsh { keyScan, err := exec.LookPath("ssh-keyscan") if err != nil { return fmt.Errorf("ssh-keyscan binary not found in path: %v", err) } - endpoint, err := transport.NewEndpoint(b.ScmRepository) + endpoint, err := transport.NewEndpoint(ptr.To(b.ScmRepository)) if err != nil { return fmt.Errorf("transport.NewEndpoint failed: %v", err) } @@ -80,7 +80,7 @@ func (b Builder) initToken() error { defer func() { _ = privateKeyObj.Close() // nolint: errcheck }() - _, err = privateKeyObj.WriteString(b.ScmSshKey) + _, err = privateKeyObj.WriteString(ptr.To(b.ScmSshKey)) if err != nil { return fmt.Errorf("Write private key failed: %v", err) } diff --git a/go.mod b/go.mod index f8793af1..917b0edc 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( github.com/golang-migrate/migrate/v4 v4.16.2 github.com/google/go-github/v53 v53.2.0 github.com/google/uuid v1.3.1 + github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b github.com/hashicorp/golang-lru/v2 v2.0.6 github.com/hibiken/asynq v0.24.1 github.com/jackc/pgx/v4 v4.18.1 diff --git a/go.sum b/go.sum index 6dc2d318..9c922aff 100644 --- a/go.sum +++ b/go.sum @@ -477,6 +477,8 @@ github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfre github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4= +github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= diff --git a/pkg/builder/builder.go b/pkg/builder/builder.go index d25b0faf..e621484f 100644 --- a/pkg/builder/builder.go +++ b/pkg/builder/builder.go @@ -22,7 +22,7 @@ import ( corev1 "k8s.io/api/core/v1" - builderlogger "github.com/go-sigma/sigma/pkg/builder/logger" + "github.com/go-sigma/sigma/pkg/builder/logger" "github.com/go-sigma/sigma/pkg/configs" "github.com/go-sigma/sigma/pkg/types" "github.com/go-sigma/sigma/pkg/utils" @@ -68,23 +68,15 @@ func Initialize() error { if err != nil { return err } - return builderlogger.Initialize() + return logger.Initialize() } // BuildEnv ... func BuildEnv(builderConfig BuilderConfig) []string { buildConfigEnvs := []string{ - fmt.Sprintf("ID=%d", builderConfig.BuilderID), + fmt.Sprintf("BUILDER_ID=%d", builderConfig.BuilderID), fmt.Sprintf("RUNNER_ID=%d", builderConfig.RunnerID), - fmt.Sprintf("SCM_CREDENTIAL_TYPE=%s", builderConfig.ScmCredentialType.String()), - fmt.Sprintf("SCM_USERNAME=%s", builderConfig.ScmUsername), - fmt.Sprintf("SCM_PROVIDER=%s", builderConfig.ScmProvider.String()), - fmt.Sprintf("SCM_REPOSITORY=%s", builderConfig.ScmRepository), - fmt.Sprintf("SCM_BRANCH=%s", ptr.To(builderConfig.ScmBranch)), - fmt.Sprintf("SCM_DEPTH=%d", builderConfig.ScmDepth), - fmt.Sprintf("SCM_SUBMODULE=%t", builderConfig.ScmSubmodule), - fmt.Sprintf("OCI_REGISTRY_DOMAIN=%s", strings.Join(builderConfig.OciRegistryDomain, ",")), fmt.Sprintf("OCI_REGISTRY_USERNAME=%s", strings.Join(builderConfig.OciRegistryUsername, ",")), fmt.Sprintf("OCI_NAME=%s", builderConfig.OciName), @@ -94,18 +86,43 @@ func BuildEnv(builderConfig BuilderConfig) []string { fmt.Sprintf("BUILDKIT_CONTEXT=%s", builderConfig.BuildkitContext), fmt.Sprintf("BUILDKIT_DOCKERFILE=%s", builderConfig.BuildkitDockerfile), fmt.Sprintf("BUILDKIT_PLATFORMS=%s", utils.StringsJoin(builderConfig.BuildkitPlatforms, ",")), + fmt.Sprintf("BUILDKIT_BUILD_ARGS=%s", strings.Join(builderConfig.BuildkitBuildArgs, ",")), + } + if builderConfig.Dockerfile != nil { + buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("DOCKERFILE=%s", ptr.To(builderConfig.Dockerfile))) + } + if builderConfig.ScmCredentialType != nil { + buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_CREDENTIAL_TYPE=%s", builderConfig.ScmCredentialType.String())) + } + if builderConfig.ScmProvider != nil { + buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_PROVIDER=%s", builderConfig.ScmProvider.String())) + } + if builderConfig.ScmRepository != nil { + buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_REPOSITORY=%s", ptr.To(builderConfig.ScmRepository))) + } + if builderConfig.ScmBranch != nil { + buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_BRANCH=%s", ptr.To(builderConfig.ScmBranch))) + } + if builderConfig.ScmDepth != nil { + buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_DEPTH=%d", ptr.To(builderConfig.ScmDepth))) + } + if builderConfig.ScmSubmodule != nil { + buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_SUBMODULE=%t", ptr.To(builderConfig.ScmSubmodule))) + } + if builderConfig.ScmUsername != nil { + buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_USERNAME=%s", ptr.To(builderConfig.ScmUsername))) } - if builderConfig.ScmPassword != "" { + if builderConfig.ScmPassword != nil { buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_PASSWORD=%s", crypt.MustEncrypt( - fmt.Sprintf("%d-%d", builderConfig.BuilderID, builderConfig.RunnerID), builderConfig.ScmPassword))) + fmt.Sprintf("%d-%d", builderConfig.BuilderID, builderConfig.RunnerID), ptr.To(builderConfig.ScmPassword)))) } - if builderConfig.ScmSshKey != "" { + if builderConfig.ScmSshKey != nil { buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_SSH_KEY=%s", crypt.MustEncrypt( - fmt.Sprintf("%d-%d", builderConfig.BuilderID, builderConfig.RunnerID), builderConfig.ScmSshKey))) + fmt.Sprintf("%d-%d", builderConfig.BuilderID, builderConfig.RunnerID), ptr.To(builderConfig.ScmSshKey)))) } - if builderConfig.ScmToken != "" { + if builderConfig.ScmToken != nil { buildConfigEnvs = append(buildConfigEnvs, fmt.Sprintf("SCM_TOKEN=%s", crypt.MustEncrypt( - fmt.Sprintf("%d-%d", builderConfig.BuilderID, builderConfig.RunnerID), builderConfig.ScmToken))) + fmt.Sprintf("%d-%d", builderConfig.BuilderID, builderConfig.RunnerID), ptr.To(builderConfig.ScmToken)))) } if len(builderConfig.OciRegistryPassword) != 0 { var passwords []string diff --git a/pkg/daemon/builder/builder.go b/pkg/daemon/builder/builder.go index e9180104..1e9de8a9 100644 --- a/pkg/daemon/builder/builder.go +++ b/pkg/daemon/builder/builder.go @@ -22,13 +22,12 @@ import ( "github.com/hibiken/asynq" "github.com/rs/zerolog/log" - builderdriver "github.com/go-sigma/sigma/pkg/builder" + "github.com/go-sigma/sigma/pkg/builder" "github.com/go-sigma/sigma/pkg/daemon" "github.com/go-sigma/sigma/pkg/dal/dao" "github.com/go-sigma/sigma/pkg/types" "github.com/go-sigma/sigma/pkg/types/enums" "github.com/go-sigma/sigma/pkg/utils" - "github.com/go-sigma/sigma/pkg/utils/ptr" ) func init() { @@ -41,19 +40,19 @@ func builderRunner(ctx context.Context, task *asynq.Task) error { if err != nil { return fmt.Errorf("Unmarshal payload failed: %v", err) } - b := builder{ + b := runner{ builderServiceFactory: dao.NewBuilderServiceFactory(), } return b.runner(ctx, payload) } -type builder struct { +type runner struct { builderServiceFactory dao.BuilderServiceFactory } -func (b builder) runner(ctx context.Context, payload types.DaemonBuilderPayload) error { +func (b runner) runner(ctx context.Context, payload types.DaemonBuilderPayload) error { if payload.Action == enums.DaemonBuilderActionStop { - return builderdriver.Driver.Stop(ctx, payload.BuilderID, payload.RunnerID) + return builder.Driver.Stop(ctx, payload.BuilderID, payload.RunnerID) } builderService := b.builderServiceFactory.New() builderObj, err := builderService.GetByRepositoryID(ctx, payload.RepositoryID) @@ -78,7 +77,7 @@ func (b builder) runner(ctx context.Context, payload types.DaemonBuilderPayload) // return fmt.Errorf("Create builder runner record failed: %v", err) // } - buildConfig := builderdriver.BuilderConfig{ + buildConfig := builder.BuilderConfig{ Builder: types.Builder{ BuilderID: payload.BuilderID, RunnerID: runnerObj.ID, @@ -91,7 +90,7 @@ func (b builder) runner(ctx context.Context, payload types.DaemonBuilderPayload) // ScmPassword: builderObj.ScmPassword, // ScmRepository: builderObj.ScmRepository, ScmBranch: runnerObj.ScmBranch, - ScmDepth: ptr.To(builderObj.ScmDepth), + ScmDepth: builderObj.ScmDepth, // ScmSubmodule: builderObj.ScmSubmodule, OciRegistryDomain: []string{"192.168.31.114:3000"}, @@ -103,9 +102,9 @@ func (b builder) runner(ctx context.Context, payload types.DaemonBuilderPayload) }, } if payload.Action == enums.DaemonBuilderActionStart { // nolint: gocritic - err = builderdriver.Driver.Start(ctx, buildConfig) + err = builder.Driver.Start(ctx, buildConfig) } else if payload.Action == enums.DaemonBuilderActionRestart { - err = builderdriver.Driver.Start(ctx, buildConfig) + err = builder.Driver.Start(ctx, buildConfig) } else { log.Error().Err(err).Str("action", payload.Action.String()).Msg("Daemon builder action not found") return fmt.Errorf("Daemon builder action not found") diff --git a/pkg/dal/migrations/mysql/0001_initialize.up.sql b/pkg/dal/migrations/mysql/0001_initialize.up.sql index 5821372b..7efe69bc 100644 --- a/pkg/dal/migrations/mysql/0001_initialize.up.sql +++ b/pkg/dal/migrations/mysql/0001_initialize.up.sql @@ -396,6 +396,7 @@ CREATE TABLE IF NOT EXISTS `builder_runners` ( `scm_branch` varchar(30), `started_at` timestamp, `ended_at` timestamp, + `duration` bigint, -- other fields `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, diff --git a/pkg/dal/migrations/postgresql/0001_initialize.up.sql b/pkg/dal/migrations/postgresql/0001_initialize.up.sql index 78000660..d96c629c 100644 --- a/pkg/dal/migrations/postgresql/0001_initialize.up.sql +++ b/pkg/dal/migrations/postgresql/0001_initialize.up.sql @@ -465,6 +465,7 @@ CREATE TABLE IF NOT EXISTS "builder_runners" ( "scm_branch" varchar(30), "started_at" timestamp, "ended_at" timestamp, + "duration" bigint, -- other fields "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL, diff --git a/pkg/dal/migrations/sqlite3/0001_initialize.up.sql b/pkg/dal/migrations/sqlite3/0001_initialize.up.sql index 57122f1e..ab32ae08 100644 --- a/pkg/dal/migrations/sqlite3/0001_initialize.up.sql +++ b/pkg/dal/migrations/sqlite3/0001_initialize.up.sql @@ -378,14 +378,14 @@ CREATE TABLE IF NOT EXISTS `builders` ( -- other fields `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `deleted_at` bigint NOT NULL DEFAULT 0, + `deleted_at` integer NOT NULL DEFAULT 0, FOREIGN KEY (`repository_id`) REFERENCES `repositories` (`id`), CONSTRAINT `builders_unique_with_repository` UNIQUE (`repository_id`, `deleted_at`) ); CREATE TABLE IF NOT EXISTS `builder_runners` ( `id` integer PRIMARY KEY AUTOINCREMENT, - `builder_id` bigint NOT NULL, + `builder_id` integer NOT NULL, `log` BLOB, `status` text CHECK (`status` IN ('Success', 'Failed', 'Pending', 'Scheduling', 'Building')) NOT NULL DEFAULT 'Pending', -- common settings @@ -394,10 +394,11 @@ CREATE TABLE IF NOT EXISTS `builder_runners` ( `scm_branch` varchar(30), `started_at` timestamp, `ended_at` timestamp, + `duration` integer, -- other fields `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `deleted_at` bigint NOT NULL DEFAULT 0, + `deleted_at` integer NOT NULL DEFAULT 0, FOREIGN KEY (`builder_id`) REFERENCES `builders` (`id`) ); diff --git a/pkg/dal/models/builder.go b/pkg/dal/models/builder.go index f9c78125..f2950545 100644 --- a/pkg/dal/models/builder.go +++ b/pkg/dal/models/builder.go @@ -88,6 +88,7 @@ type BuilderRunner struct { StartedAt *time.Time EndedAt *time.Time + Duration *int64 Builder Builder } diff --git a/pkg/dal/query/builder_runners.gen.go b/pkg/dal/query/builder_runners.gen.go index c728339a..670d676d 100644 --- a/pkg/dal/query/builder_runners.gen.go +++ b/pkg/dal/query/builder_runners.gen.go @@ -39,6 +39,7 @@ func newBuilderRunner(db *gorm.DB, opts ...gen.DOOption) builderRunner { _builderRunner.ScmBranch = field.NewString(tableName, "scm_branch") _builderRunner.StartedAt = field.NewTime(tableName, "started_at") _builderRunner.EndedAt = field.NewTime(tableName, "ended_at") + _builderRunner.Duration = field.NewInt64(tableName, "duration") _builderRunner.Builder = builderRunnerBelongsToBuilder{ db: db.Session(&gorm.Session{}), @@ -87,6 +88,7 @@ type builderRunner struct { ScmBranch field.String StartedAt field.Time EndedAt field.Time + Duration field.Int64 Builder builderRunnerBelongsToBuilder fieldMap map[string]field.Expr @@ -116,6 +118,7 @@ func (b *builderRunner) updateTableName(table string) *builderRunner { b.ScmBranch = field.NewString(table, "scm_branch") b.StartedAt = field.NewTime(table, "started_at") b.EndedAt = field.NewTime(table, "ended_at") + b.Duration = field.NewInt64(table, "duration") b.fillFieldMap() @@ -144,7 +147,7 @@ func (b *builderRunner) GetFieldByName(fieldName string) (field.OrderExpr, bool) } func (b *builderRunner) fillFieldMap() { - b.fieldMap = make(map[string]field.Expr, 13) + b.fieldMap = make(map[string]field.Expr, 14) b.fieldMap["created_at"] = b.CreatedAt b.fieldMap["updated_at"] = b.UpdatedAt b.fieldMap["deleted_at"] = b.DeletedAt @@ -157,6 +160,7 @@ func (b *builderRunner) fillFieldMap() { b.fieldMap["scm_branch"] = b.ScmBranch b.fieldMap["started_at"] = b.StartedAt b.fieldMap["ended_at"] = b.EndedAt + b.fieldMap["duration"] = b.Duration } diff --git a/pkg/handlers/apidocs/docs.go b/pkg/handlers/apidocs/docs.go index d8037fc9..f5f2f565 100644 --- a/pkg/handlers/apidocs/docs.go +++ b/pkg/handlers/apidocs/docs.go @@ -616,6 +616,80 @@ const docTemplate = `{ } } }, + "/namespace/{namespace_id}/repositories/{repository_id}/builders/{id}": { + "put": { + "security": [ + { + "BasicAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builder" + ], + "summary": "Update a builder by id", + "parameters": [ + { + "type": "string", + "description": "Namespace ID", + "name": "namespace_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Repository ID", + "name": "repository_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Builder ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Builder object", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.PutBuilderRequestSwagger" + } + } + ], + "responses": { + "201": { + "description": "Created" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + } + } + } + }, "/namespaces/": { "get": { "security": [ @@ -916,6 +990,135 @@ const docTemplate = `{ } } }, + "/namespaces/{namespace_id}/repositories/{repository_id}/builders": { + "post": { + "security": [ + { + "BasicAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builder" + ], + "summary": "Create a builder for repository", + "parameters": [ + { + "type": "string", + "description": "Namespace ID", + "name": "namespace_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Repository ID", + "name": "repository_id", + "in": "path", + "required": true + }, + { + "description": "Builder object", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.PostBuilderRequestSwagger" + } + } + ], + "responses": { + "201": { + "description": "Created" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + } + } + } + }, + "/namespaces/{namespace_id}/repositories/{repository_id}/builders/{builder_id}/runners/": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builder" + ], + "summary": "Get builder runners by builder id", + "parameters": [ + { + "type": "string", + "description": "Namespace ID", + "name": "namespace_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Repository ID", + "name": "repository_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Builder ID", + "name": "builder_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.BuilderItem" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + } + } + } + }, "/namespaces/{namespace}/repositories/": { "get": { "security": [ @@ -1610,181 +1813,6 @@ const docTemplate = `{ } } }, - "/repositories/{repository_id}/builders": { - "post": { - "security": [ - { - "BasicAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Builder" - ], - "summary": "Create a builder for repository", - "parameters": [ - { - "type": "string", - "description": "Repository ID", - "name": "repository_id", - "in": "path", - "required": true - }, - { - "description": "Builder object", - "name": "message", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/types.PostBuilderRequestSwagger" - } - } - ], - "responses": { - "201": { - "description": "Created" - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - } - } - } - }, - "/repositories/{repository_id}/builders/": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Builder" - ], - "summary": "Get a builder by builder id", - "parameters": [ - { - "type": "string", - "description": "Repository ID", - "name": "repository_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/types.BuilderItem" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - } - } - } - }, - "/repositories/{repository_id}/builders/{id}": { - "put": { - "security": [ - { - "BasicAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Builder" - ], - "summary": "Update a builder by id", - "parameters": [ - { - "type": "string", - "description": "Repository ID", - "name": "repository_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Builder ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Builder object", - "name": "message", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/types.PutBuilderRequestSwagger" - } - } - ], - "responses": { - "201": { - "description": "Created" - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - } - } - } - }, "/systems/endpoint": { "get": { "consumes": [ diff --git a/pkg/handlers/apidocs/swagger.json b/pkg/handlers/apidocs/swagger.json index ba35c1d7..bc2b8751 100644 --- a/pkg/handlers/apidocs/swagger.json +++ b/pkg/handlers/apidocs/swagger.json @@ -607,6 +607,80 @@ } } }, + "/namespace/{namespace_id}/repositories/{repository_id}/builders/{id}": { + "put": { + "security": [ + { + "BasicAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builder" + ], + "summary": "Update a builder by id", + "parameters": [ + { + "type": "string", + "description": "Namespace ID", + "name": "namespace_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Repository ID", + "name": "repository_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Builder ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Builder object", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.PutBuilderRequestSwagger" + } + } + ], + "responses": { + "201": { + "description": "Created" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + } + } + } + }, "/namespaces/": { "get": { "security": [ @@ -907,6 +981,135 @@ } } }, + "/namespaces/{namespace_id}/repositories/{repository_id}/builders": { + "post": { + "security": [ + { + "BasicAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builder" + ], + "summary": "Create a builder for repository", + "parameters": [ + { + "type": "string", + "description": "Namespace ID", + "name": "namespace_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Repository ID", + "name": "repository_id", + "in": "path", + "required": true + }, + { + "description": "Builder object", + "name": "message", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.PostBuilderRequestSwagger" + } + } + ], + "responses": { + "201": { + "description": "Created" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + } + } + } + }, + "/namespaces/{namespace_id}/repositories/{repository_id}/builders/{builder_id}/runners/": { + "get": { + "security": [ + { + "BasicAuth": [] + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Builder" + ], + "summary": "Get builder runners by builder id", + "parameters": [ + { + "type": "string", + "description": "Namespace ID", + "name": "namespace_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Repository ID", + "name": "repository_id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Builder ID", + "name": "builder_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.BuilderItem" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/xerrors.ErrCode" + } + } + } + } + }, "/namespaces/{namespace}/repositories/": { "get": { "security": [ @@ -1601,181 +1804,6 @@ } } }, - "/repositories/{repository_id}/builders": { - "post": { - "security": [ - { - "BasicAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Builder" - ], - "summary": "Create a builder for repository", - "parameters": [ - { - "type": "string", - "description": "Repository ID", - "name": "repository_id", - "in": "path", - "required": true - }, - { - "description": "Builder object", - "name": "message", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/types.PostBuilderRequestSwagger" - } - } - ], - "responses": { - "201": { - "description": "Created" - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - } - } - } - }, - "/repositories/{repository_id}/builders/": { - "get": { - "security": [ - { - "BasicAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Builder" - ], - "summary": "Get a builder by builder id", - "parameters": [ - { - "type": "string", - "description": "Repository ID", - "name": "repository_id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/types.BuilderItem" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - } - } - } - }, - "/repositories/{repository_id}/builders/{id}": { - "put": { - "security": [ - { - "BasicAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Builder" - ], - "summary": "Update a builder by id", - "parameters": [ - { - "type": "string", - "description": "Repository ID", - "name": "repository_id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "Builder ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "Builder object", - "name": "message", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/types.PutBuilderRequestSwagger" - } - } - ], - "responses": { - "201": { - "description": "Created" - }, - "400": { - "description": "Bad Request", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "404": { - "description": "Not Found", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - }, - "500": { - "description": "Internal Server Error", - "schema": { - "$ref": "#/definitions/xerrors.ErrCode" - } - } - } - } - }, "/systems/endpoint": { "get": { "consumes": [ diff --git a/pkg/handlers/apidocs/swagger.yaml b/pkg/handlers/apidocs/swagger.yaml index bbab36b2..571c01c6 100644 --- a/pkg/handlers/apidocs/swagger.yaml +++ b/pkg/handlers/apidocs/swagger.yaml @@ -1513,6 +1513,54 @@ paths: summary: Get logs tags: - Daemon + /namespace/{namespace_id}/repositories/{repository_id}/builders/{id}: + put: + consumes: + - application/json + parameters: + - description: Namespace ID + in: path + name: namespace_id + required: true + type: string + - description: Repository ID + in: path + name: repository_id + required: true + type: string + - description: Builder ID + in: path + name: id + required: true + type: string + - description: Builder object + in: body + name: message + required: true + schema: + $ref: '#/definitions/types.PutBuilderRequestSwagger' + produces: + - application/json + responses: + "201": + description: Created + "400": + description: Bad Request + schema: + $ref: '#/definitions/xerrors.ErrCode' + "404": + description: Not Found + schema: + $ref: '#/definitions/xerrors.ErrCode' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/xerrors.ErrCode' + security: + - BasicAuth: [] + summary: Update a builder by id + tags: + - Builder /namespaces/: get: consumes: @@ -1666,6 +1714,89 @@ paths: summary: Update namespace tags: - Namespace + /namespaces/{namespace_id}/repositories/{repository_id}/builders: + post: + consumes: + - application/json + parameters: + - description: Namespace ID + in: path + name: namespace_id + required: true + type: string + - description: Repository ID + in: path + name: repository_id + required: true + type: string + - description: Builder object + in: body + name: message + required: true + schema: + $ref: '#/definitions/types.PostBuilderRequestSwagger' + produces: + - application/json + responses: + "201": + description: Created + "400": + description: Bad Request + schema: + $ref: '#/definitions/xerrors.ErrCode' + "404": + description: Not Found + schema: + $ref: '#/definitions/xerrors.ErrCode' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/xerrors.ErrCode' + security: + - BasicAuth: [] + summary: Create a builder for repository + tags: + - Builder + /namespaces/{namespace_id}/repositories/{repository_id}/builders/{builder_id}/runners/: + get: + consumes: + - application/json + parameters: + - description: Namespace ID + in: path + name: namespace_id + required: true + type: string + - description: Repository ID + in: path + name: repository_id + required: true + type: string + - description: Builder ID + in: path + name: builder_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.BuilderItem' + "404": + description: Not Found + schema: + $ref: '#/definitions/xerrors.ErrCode' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/xerrors.ErrCode' + security: + - BasicAuth: [] + summary: Get builder runners by builder id + tags: + - Builder /namespaces/{namespace}/repositories/: get: consumes: @@ -2139,117 +2270,6 @@ paths: summary: Redirect oauth2 provider callback tags: - OAuth2 - /repositories/{repository_id}/builders: - post: - consumes: - - application/json - parameters: - - description: Repository ID - in: path - name: repository_id - required: true - type: string - - description: Builder object - in: body - name: message - required: true - schema: - $ref: '#/definitions/types.PostBuilderRequestSwagger' - produces: - - application/json - responses: - "201": - description: Created - "400": - description: Bad Request - schema: - $ref: '#/definitions/xerrors.ErrCode' - "404": - description: Not Found - schema: - $ref: '#/definitions/xerrors.ErrCode' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/xerrors.ErrCode' - security: - - BasicAuth: [] - summary: Create a builder for repository - tags: - - Builder - /repositories/{repository_id}/builders/: - get: - consumes: - - application/json - parameters: - - description: Repository ID - in: path - name: repository_id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/types.BuilderItem' - "404": - description: Not Found - schema: - $ref: '#/definitions/xerrors.ErrCode' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/xerrors.ErrCode' - security: - - BasicAuth: [] - summary: Get a builder by builder id - tags: - - Builder - /repositories/{repository_id}/builders/{id}: - put: - consumes: - - application/json - parameters: - - description: Repository ID - in: path - name: repository_id - required: true - type: string - - description: Builder ID - in: path - name: id - required: true - type: string - - description: Builder object - in: body - name: message - required: true - schema: - $ref: '#/definitions/types.PutBuilderRequestSwagger' - produces: - - application/json - responses: - "201": - description: Created - "400": - description: Bad Request - schema: - $ref: '#/definitions/xerrors.ErrCode' - "404": - description: Not Found - schema: - $ref: '#/definitions/xerrors.ErrCode' - "500": - description: Internal Server Error - schema: - $ref: '#/definitions/xerrors.ErrCode' - security: - - BasicAuth: [] - summary: Update a builder by id - tags: - - Builder /systems/endpoint: get: consumes: diff --git a/pkg/handlers/builders/builders_get.go b/pkg/handlers/builders/builders_get.go deleted file mode 100644 index 424d1a9d..00000000 --- a/pkg/handlers/builders/builders_get.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2023 sigma -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package builders - -import ( - "errors" - "fmt" - "net/http" - "strings" - - "github.com/labstack/echo/v4" - "github.com/rs/zerolog/log" - "gorm.io/gorm" - - "github.com/go-sigma/sigma/pkg/types" - "github.com/go-sigma/sigma/pkg/types/enums" - "github.com/go-sigma/sigma/pkg/utils" - "github.com/go-sigma/sigma/pkg/utils/ptr" - "github.com/go-sigma/sigma/pkg/xerrors" -) - -// GetBuilder handles the get builder request -// @Summary Get a builder by builder id -// @Tags Builder -// @security BasicAuth -// @Accept json -// @Produce json -// @Router /repositories/{repository_id}/builders/ [get] -// @Param repository_id path string true "Repository ID" -// @Success 200 {object} types.BuilderItem -// @Failure 404 {object} xerrors.ErrCode -// @Failure 500 {object} xerrors.ErrCode -func (h *handlers) GetBuilder(c echo.Context) error { - ctx := log.Logger.WithContext(c.Request().Context()) - - var req types.GetBuilderRequest - err := utils.BindValidate(c, &req) - if err != nil { - log.Error().Err(err).Msg("Bind and validate request body failed") - return xerrors.NewHTTPError(c, xerrors.HTTPErrCodeBadRequest, fmt.Sprintf("Bind and validate request body failed: %v", err)) - } - - builderService := h.builderServiceFactory.New() - builderObj, err := builderService.Get(ctx, req.RepositoryID) - if err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - log.Error().Err(err).Int64("repositoryID", req.RepositoryID).Msg("Builder not found") - return xerrors.NewHTTPError(c, xerrors.HTTPErrCodeNotFound, fmt.Sprintf("Builder(%d) not found: %s", req.RepositoryID, err)) - } - log.Error().Err(err).Int64("repositoryID", req.RepositoryID).Msg("Get builder failed") - return xerrors.NewHTTPError(c, xerrors.HTTPErrCodeInternalError, fmt.Sprintf("Builder(%d) not found: %s", req.RepositoryID, err)) - } - - if builderObj.RepositoryID != req.RepositoryID { - log.Error().Int64("repositoryID", req.RepositoryID).Msg("Builder not found") - return xerrors.NewHTTPError(c, xerrors.HTTPErrCodeNotFound, fmt.Sprintf("Builder(%d) not found", req.RepositoryID)) - } - - platforms := []enums.OciPlatform{} - for _, p := range strings.Split(builderObj.BuildkitPlatforms, ",") { - platforms = append(platforms, enums.OciPlatform(p)) - } - - return c.JSON(http.StatusOK, types.BuilderItem{ - ID: builderObj.ID, - RepositoryID: builderObj.RepositoryID, - - Source: builderObj.Source, - - CodeRepositoryID: builderObj.CodeRepositoryID, - - Dockerfile: ptr.Of(string(builderObj.Dockerfile)), - - ScmRepository: builderObj.ScmRepository, - ScmCredentialType: builderObj.ScmCredentialType, - ScmSshKey: builderObj.ScmSshKey, - ScmToken: builderObj.ScmToken, - ScmUsername: builderObj.ScmUsername, - ScmPassword: builderObj.ScmPassword, - - ScmBranch: builderObj.ScmBranch, - - ScmDepth: builderObj.ScmDepth, - ScmSubmodule: builderObj.ScmSubmodule, - - CronRule: builderObj.CronRule, - CronBranch: builderObj.CronBranch, - CronTagTemplate: builderObj.CronTagTemplate, - - WebhookBranchName: builderObj.WebhookBranchName, - WebhookBranchTagTemplate: builderObj.WebhookBranchTagTemplate, - WebhookTagTagTemplate: builderObj.WebhookTagTagTemplate, - - BuildkitInsecureRegistries: strings.Split(builderObj.BuildkitInsecureRegistries, ","), - BuildkitContext: builderObj.BuildkitContext, - BuildkitDockerfile: builderObj.BuildkitDockerfile, - BuildkitPlatforms: platforms, - BuildkitBuildArgs: builderObj.BuildkitBuildArgs, - }) -} diff --git a/pkg/handlers/builders/builders_post.go b/pkg/handlers/builders/builders_post.go index c67b47a2..55bd5792 100644 --- a/pkg/handlers/builders/builders_post.go +++ b/pkg/handlers/builders/builders_post.go @@ -41,7 +41,8 @@ import ( // @security BasicAuth // @Accept json // @Produce json -// @Router /repositories/{repository_id}/builders [post] +// @Router /namespaces/{namespace_id}/repositories/{repository_id}/builders [post] +// @Param namespace_id path string true "Namespace ID" // @Param repository_id path string true "Repository ID" // @Param message body types.PostBuilderRequestSwagger true "Builder object" // @Success 201 diff --git a/pkg/handlers/builders/builders_put.go b/pkg/handlers/builders/builders_put.go index 851ae55a..5a2ccf7f 100644 --- a/pkg/handlers/builders/builders_put.go +++ b/pkg/handlers/builders/builders_put.go @@ -36,7 +36,8 @@ import ( // @security BasicAuth // @Accept json // @Produce json -// @Router /repositories/{repository_id}/builders/{id} [put] +// @Router /namespace/{namespace_id}/repositories/{repository_id}/builders/{id} [put] +// @Param namespace_id path string true "Namespace ID" // @Param repository_id path string true "Repository ID" // @Param id path string true "Builder ID" // @Param message body types.PutBuilderRequestSwagger true "Builder object" diff --git a/pkg/handlers/builders/builders_runners_list.go b/pkg/handlers/builders/builders_runners_list.go index cb756f71..8707be55 100644 --- a/pkg/handlers/builders/builders_runners_list.go +++ b/pkg/handlers/builders/builders_runners_list.go @@ -18,7 +18,9 @@ import ( "errors" "fmt" "net/http" + "time" + "github.com/hako/durafmt" "github.com/labstack/echo/v4" "github.com/rs/zerolog/log" "gorm.io/gorm" @@ -31,6 +33,18 @@ import ( ) // ListRunners handles the list builder runners request +// @Summary Get builder runners by builder id +// @Tags Builder +// @security BasicAuth +// @Accept json +// @Produce json +// @Router /namespaces/{namespace_id}/repositories/{repository_id}/builders/{builder_id}/runners/ [get] +// @Param namespace_id path string true "Namespace ID" +// @Param repository_id path string true "Repository ID" +// @Param builder_id path string true "Builder ID" +// @Success 200 {object} types.BuilderItem +// @Failure 404 {object} xerrors.ErrCode +// @Failure 500 {object} xerrors.ErrCode func (h *handlers) ListRunners(c echo.Context) error { ctx := log.Logger.WithContext(c.Request().Context()) @@ -48,32 +62,44 @@ func (h *handlers) ListRunners(c echo.Context) error { log.Error().Err(err).Int64("id", req.RepositoryID).Msg("Get builder by repository id failed") return xerrors.NewHTTPError(c, xerrors.HTTPErrCodeInternalError, fmt.Sprintf("Get builder by repository id failed: %v", err)) } - runnerObjs, total, err := builderService.ListRunners(ctx, req.ID, req.Pagination, req.Sortable) + runnerObjs, total, err := builderService.ListRunners(ctx, req.BuilderID, req.Pagination, req.Sortable) if err != nil { log.Error().Err(err).Msg("List builder runners failed") return xerrors.NewHTTPError(c, xerrors.HTTPErrCodeInternalError, fmt.Sprintf("List builder runners failed: %v", err)) } var resp = make([]any, 0, len(runnerObjs)) - for _, runner := range runnerObjs { + for _, runnerObj := range runnerObjs { var startedAt, endedAt string - if runner.StartedAt != nil { - startedAt = runner.StartedAt.Format(consts.DefaultTimePattern) + if runnerObj.StartedAt != nil { + startedAt = runnerObj.StartedAt.Format(consts.DefaultTimePattern) } - if runner.EndedAt != nil { - endedAt = runner.EndedAt.Format(consts.DefaultTimePattern) + if runnerObj.EndedAt != nil { + endedAt = runnerObj.EndedAt.Format(consts.DefaultTimePattern) } + + var duration *string + if runnerObj.Duration != nil { + duration = ptr.Of(durafmt.ParseShort(time.Millisecond * time.Duration(ptr.To(runnerObj.Duration))).String()) + } + resp = append(resp, types.BuilderRunnerItem{ - ID: runner.ID, - BuilderID: runner.BuilderID, - Log: runner.Log, - Status: runner.Status, - Tag: runner.Tag, - Description: runner.Description, - ScmBranch: runner.ScmBranch, + ID: runnerObj.ID, + BuilderID: runnerObj.BuilderID, + + Log: runnerObj.Log, + + Status: runnerObj.Status, + Tag: runnerObj.Tag, + Description: runnerObj.Description, + ScmBranch: runnerObj.ScmBranch, + StartedAt: ptr.Of(startedAt), EndedAt: ptr.Of(endedAt), - CreatedAt: runner.CreatedAt.Format(consts.DefaultTimePattern), - UpdatedAt: runner.UpdatedAt.Format(consts.DefaultTimePattern), + RawDuration: runnerObj.Duration, + Duration: duration, + + CreatedAt: runnerObj.CreatedAt.Format(consts.DefaultTimePattern), + UpdatedAt: runnerObj.UpdatedAt.Format(consts.DefaultTimePattern), }) } return c.JSON(http.StatusOK, types.CommonList{Total: total, Items: resp}) diff --git a/pkg/handlers/builders/handler.go b/pkg/handlers/builders/handler.go index 613b5001..40b8f6eb 100644 --- a/pkg/handlers/builders/handler.go +++ b/pkg/handlers/builders/handler.go @@ -31,8 +31,6 @@ import ( type Handlers interface { // PostBuilder handles the post builder request PostBuilder(c echo.Context) error - // GetBuilder handles the get builder request - GetBuilder(c echo.Context) error // PutBuilder handles the put builder request PutBuilder(c echo.Context) error // ListRunners handles the list builder runners request @@ -103,11 +101,10 @@ type factory struct{} // Initialize initializes the namespace handlers func (f factory) Initialize(e *echo.Echo) error { - builderGroup := e.Group(consts.APIV1+"/namespaces/:namespace/repositories/:repository_id/builders", middlewares.AuthWithConfig(middlewares.AuthConfig{})) + builderGroup := e.Group(consts.APIV1+"/namespaces/:namespace_id/repositories/:repository_id/builders", middlewares.AuthWithConfig(middlewares.AuthConfig{})) handler := handlerNew() builderGroup.POST("/", handler.PostBuilder) - builderGroup.GET("/", handler.GetBuilder) builderGroup.PUT("/:builder_id", handler.PutBuilder) builderGroup.GET("/:builder_id/runners/", handler.ListRunners) diff --git a/pkg/types/builder.go b/pkg/types/builder.go index ead061bc..82b5f07f 100644 --- a/pkg/types/builder.go +++ b/pkg/types/builder.go @@ -20,19 +20,23 @@ import ( // Builder config for builder type Builder struct { - BuilderID int64 `env:"ID,notEmpty"` + BuilderID int64 `env:"BUILDER_ID,notEmpty"` RunnerID int64 `env:"RUNNER_ID,notEmpty"` - ScmCredentialType enums.ScmCredentialType `env:"SCM_CREDENTIAL_TYPE,notEmpty"` - ScmSshKey string `env:"SCM_SSH_KEY"` - ScmToken string `env:"SCM_TOKEN"` - ScmUsername string `env:"SCM_USERNAME"` - ScmPassword string `env:"SCM_PASSWORD"` - ScmProvider enums.ScmProvider `env:"SCM_PROVIDER,notEmpty"` - ScmRepository string `env:"SCM_REPOSITORY,notEmpty"` - ScmBranch *string `env:"SCM_BRANCH" envDefault:"main"` - ScmDepth int `env:"SCM_DEPTH" envDefault:"0"` - ScmSubmodule bool `env:"SCM_SUBMODULE" envDefault:"false"` + Source enums.BuilderSource `env:"SOURCE,notEmpty"` + + Dockerfile *string `env:"DOCKERFILE"` + + ScmProvider *enums.ScmProvider `env:"SCM_PROVIDER"` + ScmCredentialType *enums.ScmCredentialType `env:"SCM_CREDENTIAL_TYPE,notEmpty"` + ScmSshKey *string `env:"SCM_SSH_KEY"` + ScmToken *string `env:"SCM_TOKEN"` + ScmUsername *string `env:"SCM_USERNAME"` + ScmPassword *string `env:"SCM_PASSWORD"` + ScmRepository *string `env:"SCM_REPOSITORY,notEmpty"` + ScmBranch *string `env:"SCM_BRANCH" envDefault:"main"` + ScmDepth *int `env:"SCM_DEPTH" envDefault:"0"` + ScmSubmodule *bool `env:"SCM_SUBMODULE" envDefault:"false"` OciRegistryDomain []string `env:"OCI_REGISTRY_DOMAIN" envSeparator:","` OciRegistryUsername []string `env:"OCI_REGISTRY_USERNAME" envSeparator:","` @@ -44,6 +48,7 @@ type Builder struct { BuildkitContext string `env:"BUILDKIT_CONTEXT" envDefault:"."` BuildkitDockerfile string `env:"BUILDKIT_DOCKERFILE" envDefault:"Dockerfile"` BuildkitPlatforms []enums.OciPlatform `env:"BUILDKIT_PLATFORMS" envSeparator:","` + BuildkitBuildArgs []string `env:"BUILDKIT_BUILD_ARGS" envSeparator:","` } // GetBuilderRequest represents the request to get a builder. @@ -159,23 +164,26 @@ type ListBuilderRunnersRequest struct { Pagination Sortable + NamespaceID int64 `json:"namespace_id" param:"namespace_id" validate:"required,number" example:"10"` RepositoryID int64 `json:"repository_id" param:"repository_id" validate:"required,number" example:"10"` - ID int64 `json:"id" param:"id" validate:"required,number" example:"10"` + BuilderID int64 `json:"builder_id" param:"builder_id" validate:"required,number" example:"10"` } // BuilderRunnerItem ... type BuilderRunnerItem struct { - ID int64 `json:"id" example:"10"` - BuilderID int64 - Log []byte - Status enums.BuildStatus - - Tag string - Description *string - ScmBranch *string - - StartedAt *string - EndedAt *string + ID int64 `json:"id" example:"10"` + BuilderID int64 `json:"builder_id" example:"10"` + Log []byte `json:"log" example:"log"` + Status enums.BuildStatus `json:"status" example:"Success"` + + Tag string `json:"tag" example:"v1.0"` + Description *string `json:"description" example:"description"` + ScmBranch *string `json:"scm_branch" example:"main"` + + StartedAt *string `json:"started_at" example:"2006-01-02 15:04:05"` + EndedAt *string `json:"ended_at" example:"2006-01-02 15:04:05"` + RawDuration *int64 `json:"raw_duration" example:"10"` + Duration *string `json:"duration" example:"1h"` CreatedAt string `json:"created_at" example:"2006-01-02 15:04:05"` UpdatedAt string `json:"updated_at" example:"2006-01-02 15:04:05"` diff --git a/web/src/interfaces/index.ts b/web/src/interfaces/index.ts index 294de6df..1d57b054 100644 --- a/web/src/interfaces/index.ts +++ b/web/src/interfaces/index.ts @@ -260,7 +260,12 @@ export interface IBuilderItem { buildkit_platforms: string[]; } -export interface BuilderRunnerItem { +export interface IBuilderRunnerList { + items: IBuilderRunnerItem[]; + total: number; +} + +export interface IBuilderRunnerItem { id: number; builder_id: number; status: string; diff --git a/web/src/pages/Builder/RunnerList.tsx b/web/src/pages/Builder/RunnerList.tsx index 625ff21e..e2e76701 100644 --- a/web/src/pages/Builder/RunnerList.tsx +++ b/web/src/pages/Builder/RunnerList.tsx @@ -15,8 +15,9 @@ */ import axios from "axios"; -import { useNavigate } from 'react-router-dom'; +import dayjs from "dayjs"; import { useEffect, useState } from "react"; +import { useNavigate } from 'react-router-dom'; import { Helmet, HelmetProvider } from "react-helmet-async"; import { Link, useSearchParams, useParams } from "react-router-dom"; @@ -27,7 +28,7 @@ import Toast from "../../components/Notification"; import Pagination from "../../components/Pagination"; import OrderHeader from "../../components/OrderHeader"; -import { IRepositoryItem, IHTTPError, IBuilderItem, IOrder } from "../../interfaces"; +import { IRepositoryItem, IHTTPError, IBuilderItem, IOrder, IBuilderRunnerItem, IBuilderRunnerList } from "../../interfaces"; export default function ({ localServer }: { localServer: string }) { const navigate = useNavigate(); @@ -43,7 +44,7 @@ export default function ({ localServer }: { localServer: string }) { const [total, setTotal] = useState(0); useEffect(() => { - axios.get(localServer + `/api/v1/namespaces/${namespace}/repositories/${repository_id}`).then(response => { + axios.get(localServer + `/api/v1/namespaces/${repositoryObj?.namespace_id}/repositories/${repository_id}`).then(response => { if (response?.status === 200) { const r = response.data as IRepositoryItem; setRepositoryObj(r); @@ -51,7 +52,6 @@ export default function ({ localServer }: { localServer: string }) { setBuilderObj(r.builder); } } else { - console.log(response); const errorcode = response.data as IHTTPError; Toast({ level: "warning", title: errorcode.title, message: errorcode.description }); } @@ -61,10 +61,25 @@ export default function ({ localServer }: { localServer: string }) { }); }, [namespace, repository_id]); + const [runnerObjs, setRunnerObjs] = useState() + useEffect(() => { if (builderObj === undefined) { return; } + axios.get(localServer + `/api/v1/namespaces/${repositoryObj?.namespace_id}/repositories/${repository_id}/builders/${builderObj.id}/runners/`).then(response => { + if (response?.status === 200) { + const r = response.data as IBuilderRunnerList; + setRunnerObjs(r.items); + setTotal(r.total); + } else { + const errorcode = response.data as IHTTPError; + Toast({ level: "warning", title: errorcode.title, message: errorcode.description }); + } + }).catch(error => { + const errorcode = error.response.data as IHTTPError; + Toast({ level: "warning", title: errorcode.title, message: errorcode.description }); + }); }, [namespace, repository_id, builderObj]) return ( @@ -173,6 +188,9 @@ export default function ({ localServer }: { localServer: string }) { Tag + + Status + Cost @@ -190,15 +208,15 @@ export default function ({ localServer }: { localServer: string }) { - {/* - { - namespaceList.items?.map((namespace, index) => { - return ( - - ); - }) - } - */} + + { + runnerObjs?.map(runnerObj => { + return ( + + ); + }) + } + ) } @@ -211,23 +229,48 @@ export default function ({ localServer }: { localServer: string }) { ) } - {/*
-
-
-
- - -
-
*/} ) } + +function TableItem({ runnerObj }: { runnerObj: IBuilderRunnerItem }) { + console.log(runnerObj, runnerObj.tag); + + const navigate = useNavigate(); + return ( + + { + // window.open(repository.clone_url, "_blank"); + // }} + > +
+
+ + {runnerObj.tag} + {runnerObj.description} + +
+
+ + + {runnerObj.status} + + + {dayjs().to(dayjs(runnerObj.created_at))} + + + {dayjs().to(dayjs(runnerObj.created_at))} + + { + navigate("/builders/setup") + }} + > + Setup + + + ) +}