From b55aa2bb36845e95a4766a1f4d7e6abcd9d4a50c Mon Sep 17 00:00:00 2001 From: Easton Crupper <65553218+ecrupper@users.noreply.github.com> Date: Wed, 24 Apr 2024 10:44:36 -0400 Subject: [PATCH] refactor(build)!: move build from types and nest the object (#1111) * init and broken commit * working for now * integration testing fixes * more cleanup and remove repo usage where not needed * address feedback * remove redundant return on a couple extra funcs --------- Co-authored-by: David May <49894298+wass3rw3rk@users.noreply.github.com> --- api/admin/build.go | 4 +- api/build/approve.go | 2 +- api/build/auto_cancel.go | 13 +- api/build/auto_cancel_test.go | 52 +- api/build/cancel.go | 3 +- api/build/clean.go | 3 +- api/build/compile_publish.go | 13 +- api/build/create.go | 7 +- api/build/enqueue.go | 12 +- api/build/executable.go | 3 +- api/build/get_id.go | 24 +- api/build/list_org.go | 4 +- api/build/list_repo.go | 4 +- api/build/plan.go | 5 +- api/build/restart.go | 1 - api/build/update.go | 5 +- api/service/plan.go | 7 +- api/step/plan.go | 14 +- api/types/build.go | 1218 +++++++++++++++++ api/types/build_test.go | 928 +++++++++++++ api/types/executor.go | 38 +- api/types/executor_test.go | 58 - api/types/queue_build.go | 134 ++ api/types/queue_build_test.go | 126 ++ api/types/repo_test.go | 6 +- api/types/worker.go | 32 +- api/types/worker_test.go | 6 +- api/webhook/post.go | 17 +- api/worker/get.go | 4 +- api/worker/list.go | 4 +- cmd/vela-server/schedule.go | 6 +- compiler/engine.go | 2 +- compiler/native/compile.go | 2 +- compiler/native/compile_test.go | 33 +- compiler/native/environment.go | 2 +- compiler/native/environment_test.go | 21 +- compiler/native/expand_test.go | 7 +- compiler/native/native.go | 5 +- compiler/native/native_test.go | 5 +- database/build/build.go | 2 + database/build/build_test.go | 145 +- database/build/clean.go | 8 +- database/build/clean_test.go | 37 +- database/build/count_deployment_test.go | 31 +- database/build/count_org_test.go | 48 +- database/build/count_repo_test.go | 31 +- database/build/count_status_test.go | 24 +- database/build/count_test.go | 24 +- database/build/create.go | 24 +- database/build/create_test.go | 20 +- database/build/delete.go | 11 +- database/build/delete_test.go | 20 +- database/build/get.go | 17 +- database/build/get_repo.go | 16 +- database/build/get_repo_test.go | 67 +- database/build/get_test.go | 58 +- database/build/interface.go | 24 +- database/build/last_repo.go | 16 +- database/build/last_repo_test.go | 61 +- database/build/list.go | 22 +- database/build/list_dashboard.go | 14 +- database/build/list_dashboard_test.go | 37 +- database/build/list_org.go | 22 +- database/build/list_org_test.go | 118 +- database/build/list_pending_running.go | 15 +- database/build/list_pending_running_repo.go | 21 +- .../build/list_pending_running_repo_test.go | 104 +- database/build/list_pending_running_test.go | 50 +- database/build/list_repo.go | 21 +- database/build/list_repo_test.go | 75 +- database/build/list_test.go | 66 +- database/build/opts.go | 10 + database/build/update.go | 24 +- database/build/update_test.go | 22 +- database/dashboard/create.go | 3 +- database/dashboard/create_test.go | 3 +- database/dashboard/dashboard.go | 160 --- database/dashboard/dashboard_test.go | 36 - database/dashboard/delete.go | 3 +- database/dashboard/delete_test.go | 5 +- database/dashboard/get.go | 7 +- database/dashboard/get_test.go | 3 +- database/dashboard/update.go | 3 +- database/dashboard/update_test.go | 3 +- database/deployment/count_repo_test.go | 7 +- database/deployment/count_test.go | 5 +- database/deployment/create_test.go | 3 +- database/deployment/delete_test.go | 3 +- database/deployment/deployment_test.go | 49 - database/deployment/get_repo_test.go | 5 +- database/deployment/get_test.go | 3 +- database/deployment/list_repo_test.go | 7 +- database/deployment/list_test.go | 5 +- database/deployment/update_test.go | 3 +- database/hook/count_repo_test.go | 8 +- database/hook/count_test.go | 6 +- database/hook/create_test.go | 4 +- database/hook/delete_test.go | 4 +- database/hook/get_repo_test.go | 5 +- database/hook/get_test.go | 3 +- database/hook/get_webhook_test.go | 3 +- database/hook/hook_test.go | 48 - database/hook/last_repo_test.go | 5 +- database/hook/list_repo_test.go | 7 +- database/hook/list_test.go | 5 +- database/hook/update_test.go | 4 +- database/integration_test.go | 175 ++- database/log/count_build.go | 4 +- database/log/count_build_test.go | 13 +- database/log/count_test.go | 6 +- database/log/create_test.go | 5 +- database/log/delete_test.go | 4 +- database/log/get_service_test.go | 5 +- database/log/get_step_test.go | 5 +- database/log/get_test.go | 3 +- database/log/interface.go | 5 +- database/log/list_build.go | 3 +- database/log/list_build_test.go | 12 +- database/log/list_test.go | 5 +- database/log/log_test.go | 97 -- database/log/update_test.go | 5 +- database/pipeline/count_repo_test.go | 5 +- database/pipeline/count_test.go | 6 +- database/pipeline/create_test.go | 4 +- database/pipeline/delete_test.go | 4 +- database/pipeline/get_repo_test.go | 3 +- database/pipeline/get_test.go | 3 +- database/pipeline/list_repo_test.go | 5 +- database/pipeline/list_test.go | 5 +- database/pipeline/pipeline_test.go | 24 - database/pipeline/update_test.go | 4 +- database/repo/count_org_test.go | 6 +- database/repo/count_test.go | 6 +- database/repo/count_user_test.go | 18 +- database/repo/create.go | 5 +- database/repo/create_test.go | 4 +- database/repo/delete.go | 3 +- database/repo/delete_test.go | 4 +- database/repo/get.go | 12 +- database/repo/get_org.go | 12 +- database/repo/get_org_test.go | 11 +- database/repo/get_test.go | 11 +- database/repo/list.go | 9 +- database/repo/list_org.go | 9 +- database/repo/list_org_test.go | 60 +- database/repo/list_test.go | 26 +- database/repo/list_user.go | 9 +- database/repo/list_user_test.go | 62 +- database/repo/repo.go | 328 ----- database/repo/repo_test.go | 437 +----- database/repo/update.go | 5 +- database/repo/update_test.go | 3 +- database/resource.go | 1 + database/service/clean_test.go | 10 +- database/service/count_build.go | 4 +- database/service/count_build_test.go | 10 +- database/service/count_test.go | 6 +- database/service/create_test.go | 4 +- database/service/delete_test.go | 4 +- database/service/get_build.go | 3 +- database/service/get_build_test.go | 7 +- database/service/get_test.go | 3 +- database/service/interface.go | 7 +- database/service/list_build.go | 3 +- database/service/list_build_test.go | 9 +- database/service/list_image_test.go | 6 +- database/service/list_status_test.go | 6 +- database/service/list_test.go | 5 +- database/service/service_test.go | 61 - database/service/update_test.go | 4 +- database/step/clean_test.go | 10 +- database/step/count_build.go | 4 +- database/step/count_build_test.go | 10 +- database/step/count_test.go | 6 +- database/step/create_test.go | 4 +- database/step/delete_test.go | 4 +- database/step/get_build.go | 3 +- database/step/get_build_test.go | 7 +- database/step/get_test.go | 4 +- database/step/interface.go | 7 +- database/step/list_build.go | 3 +- database/step/list_build_test.go | 9 +- database/step/list_image_test.go | 6 +- database/step/list_status_test.go | 6 +- database/step/list_test.go | 5 +- database/step/step_test.go | 63 - database/step/update_test.go | 4 +- database/testutils/api_resources.go | 253 ++++ database/types/build.go | 401 ++++++ database/types/build_test.go | 309 +++++ database/types/dashboard.go | 182 +++ database/types/dashboard_test.go | 231 ++++ database/types/queue_build.go | 43 + database/types/queue_build_test.go | 58 + database/types/repo.go | 342 +++++ database/types/repo_test.go | 388 ++++++ database/types/user.go | 261 ++++ database/types/user_test.go | 292 ++++ database/types/worker.go | 192 +++ database/types/worker_test.go | 212 +++ database/user/count_test.go | 6 +- database/user/create.go | 3 +- database/user/create_test.go | 4 +- database/user/delete.go | 3 +- database/user/delete_test.go | 4 +- database/user/get.go | 3 +- database/user/get_name.go | 3 +- database/user/get_name_test.go | 3 +- database/user/get_test.go | 3 +- database/user/list.go | 3 +- database/user/list_lite.go | 3 +- database/user/list_lite_test.go | 5 +- database/user/list_test.go | 5 +- database/user/update.go | 3 +- database/user/update_test.go | 4 +- database/user/user.go | 252 ---- database/user/user_test.go | 299 ---- database/worker/create.go | 3 +- database/worker/delete.go | 3 +- database/worker/get.go | 3 +- database/worker/get_hostname.go | 3 +- database/worker/list.go | 3 +- database/worker/update.go | 3 +- database/worker/worker.go | 188 +-- database/worker/worker_test.go | 15 +- internal/webhook.go | 2 +- internal/webhook_test.go | 6 +- mock/server/build.go | 60 +- mock/server/build_test.go | 4 +- queue/models/item.go | 9 +- queue/models/item_test.go | 101 +- queue/redis/length_test.go | 1 - queue/redis/pop_test.go | 1 - queue/redis/push_test.go | 1 - queue/redis/redis_test.go | 48 +- router/middleware/build/build.go | 4 +- router/middleware/build/build_test.go | 39 +- router/middleware/build/context.go | 8 +- router/middleware/build/context_test.go | 6 +- router/middleware/logger_test.go | 14 +- router/middleware/perm/perm_test.go | 29 +- router/middleware/pipeline/pipeline.go | 7 +- router/middleware/repo/repo_test.go | 7 +- router/middleware/service/service_test.go | 16 +- router/middleware/step/step_test.go | 16 +- router/middleware/worker/worker_test.go | 5 +- scm/github/repo.go | 4 +- scm/github/repo_test.go | 49 +- scm/github/webhook.go | 8 +- scm/github/webhook_test.go | 24 +- scm/service.go | 4 +- 251 files changed, 7410 insertions(+), 3365 deletions(-) create mode 100644 api/types/build.go create mode 100644 api/types/build_test.go create mode 100644 api/types/queue_build.go create mode 100644 api/types/queue_build_test.go create mode 100644 database/testutils/api_resources.go create mode 100644 database/types/build.go create mode 100644 database/types/build_test.go create mode 100644 database/types/dashboard.go create mode 100644 database/types/dashboard_test.go create mode 100644 database/types/queue_build.go create mode 100644 database/types/queue_build_test.go create mode 100644 database/types/repo.go create mode 100644 database/types/repo_test.go create mode 100644 database/types/user.go create mode 100644 database/types/user_test.go create mode 100644 database/types/worker.go create mode 100644 database/types/worker_test.go diff --git a/api/admin/build.go b/api/admin/build.go index d77d3f4b2..5e8d06694 100644 --- a/api/admin/build.go +++ b/api/admin/build.go @@ -12,9 +12,9 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" ) // swagger:operation GET /api/v1/admin/builds/queue admin AllBuildsQueue @@ -107,7 +107,7 @@ func UpdateBuild(c *gin.Context) { ctx := c.Request.Context() // capture body from API request - input := new(library.Build) + input := new(types.Build) err := c.Bind(input) if err != nil { diff --git a/api/build/approve.go b/api/build/approve.go index c530a6e41..cd022bd79 100644 --- a/api/build/approve.go +++ b/api/build/approve.go @@ -122,7 +122,7 @@ func ApproveBuild(c *gin.Context) { ctx, queue.FromGinContext(c), database.FromContext(c), - models.ToItem(b, r), + models.ToItem(b), b.GetHost(), ) diff --git a/api/build/auto_cancel.go b/api/build/auto_cancel.go index 3e219d4b4..62b2922a1 100644 --- a/api/build/auto_cancel.go +++ b/api/build/auto_cancel.go @@ -17,13 +17,12 @@ import ( "github.com/go-vela/server/database" "github.com/go-vela/server/internal/token" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" ) // AutoCancel is a helper function that checks to see if any pending or running // builds for the repo can be replaced by the current build. -func AutoCancel(c *gin.Context, b *library.Build, rB *library.Build, r *types.Repo, cancelOpts *pipeline.CancelOptions) (bool, error) { +func AutoCancel(c *gin.Context, b *types.Build, rB *types.Build, cancelOpts *pipeline.CancelOptions) (bool, error) { // if build is the current build, continue if rB.GetID() == b.GetID() { return false, nil @@ -52,7 +51,7 @@ func AutoCancel(c *gin.Context, b *library.Build, rB *library.Build, r *types.Re } case strings.EqualFold(status, constants.StatusRunning) && cancelOpts.Running: // call cancelRunning routine for builds already running on worker - err := cancelRunning(c, rB, r) + err := cancelRunning(c, rB) if err != nil { return false, err } @@ -75,7 +74,7 @@ func AutoCancel(c *gin.Context, b *library.Build, rB *library.Build, r *types.Re // cancelRunning is a helper function that determines the executor currently running a build and sends an API call // to that executor's worker to cancel the build. -func cancelRunning(c *gin.Context, b *library.Build, r *types.Repo) error { +func cancelRunning(c *gin.Context, b *types.Build) error { e := new([]types.Executor) // retrieve the worker w, err := database.FromContext(c).GetWorkerForHostname(c, b.GetHost()) @@ -133,7 +132,7 @@ func cancelRunning(c *gin.Context, b *library.Build, r *types.Repo) error { for _, executor := range *e { // check each executor on the worker running the build to see if it's running the build we want to cancel - if strings.EqualFold(executor.Repo.GetFullName(), r.GetFullName()) && *executor.GetBuild().Number == b.GetNumber() { + if executor.Build.GetID() == b.GetID() { // prepare the request to the worker client := http.DefaultClient client.Timeout = 30 * time.Second @@ -189,7 +188,7 @@ func cancelRunning(c *gin.Context, b *library.Build, r *types.Repo) error { // isCancelable is a helper function that determines whether a `target` build should be auto-canceled // given a current build that intends to supersede it. -func isCancelable(target *library.Build, current *library.Build) bool { +func isCancelable(target *types.Build, current *types.Build) bool { switch target.GetEvent() { case constants.EventPush: // target is cancelable if current build is also a push event and the branches are the same @@ -206,7 +205,7 @@ func isCancelable(target *library.Build, current *library.Build) bool { // ShouldAutoCancel is a helper function that determines whether or not a build should be eligible to // auto cancel currently running / pending builds. -func ShouldAutoCancel(opts *pipeline.CancelOptions, b *library.Build, defaultBranch string) bool { +func ShouldAutoCancel(opts *pipeline.CancelOptions, b *types.Build, defaultBranch string) bool { // if the build is pending approval, it should always be eligible to auto cancel if strings.EqualFold(b.GetStatus(), constants.StatusPendingApproval) { return true diff --git a/api/build/auto_cancel_test.go b/api/build/auto_cancel_test.go index 23879b923..15420b04d 100644 --- a/api/build/auto_cancel_test.go +++ b/api/build/auto_cancel_test.go @@ -5,8 +5,8 @@ package build import ( "testing" + "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" ) @@ -25,17 +25,17 @@ func Test_isCancelable(t *testing.T) { tests := []struct { name string - target *library.Build - current *library.Build + target *types.Build + current *types.Build want bool }{ { name: "Wrong Event", - target: &library.Build{ + target: &types.Build{ Event: &tagEvent, Branch: &branchDev, }, - current: &library.Build{ + current: &types.Build{ Event: &pushEvent, Branch: &branchDev, }, @@ -43,11 +43,11 @@ func Test_isCancelable(t *testing.T) { }, { name: "Cancelable Push", - target: &library.Build{ + target: &types.Build{ Event: &pushEvent, Branch: &branchDev, }, - current: &library.Build{ + current: &types.Build{ Event: &pushEvent, Branch: &branchDev, }, @@ -55,11 +55,11 @@ func Test_isCancelable(t *testing.T) { }, { name: "Push Branch Mismatch", - target: &library.Build{ + target: &types.Build{ Event: &pushEvent, Branch: &branchDev, }, - current: &library.Build{ + current: &types.Build{ Event: &pushEvent, Branch: &branchPatch, }, @@ -67,11 +67,11 @@ func Test_isCancelable(t *testing.T) { }, { name: "Event Mismatch", - target: &library.Build{ + target: &types.Build{ Event: &pushEvent, Branch: &branchDev, }, - current: &library.Build{ + current: &types.Build{ Event: &pullEvent, Branch: &branchDev, HeadRef: &branchPatch, @@ -80,13 +80,13 @@ func Test_isCancelable(t *testing.T) { }, { name: "Cancelable Pull", - target: &library.Build{ + target: &types.Build{ Event: &pullEvent, Branch: &branchDev, HeadRef: &branchPatch, EventAction: &actionOpened, }, - current: &library.Build{ + current: &types.Build{ Event: &pullEvent, Branch: &branchDev, HeadRef: &branchPatch, @@ -96,13 +96,13 @@ func Test_isCancelable(t *testing.T) { }, { name: "Pull Head Ref Mismatch", - target: &library.Build{ + target: &types.Build{ Event: &pullEvent, Branch: &branchDev, HeadRef: &branchPatch, EventAction: &actionSync, }, - current: &library.Build{ + current: &types.Build{ Event: &pullEvent, Branch: &branchDev, HeadRef: &branchDev, @@ -112,13 +112,13 @@ func Test_isCancelable(t *testing.T) { }, { name: "Pull Ineligible Action", - target: &library.Build{ + target: &types.Build{ Event: &pullEvent, Branch: &branchDev, HeadRef: &branchPatch, EventAction: &actionEdited, }, - current: &library.Build{ + current: &types.Build{ Event: &pullEvent, Branch: &branchDev, HeadRef: &branchDev, @@ -154,7 +154,7 @@ func Test_ShouldAutoCancel(t *testing.T) { tests := []struct { name string opts *pipeline.CancelOptions - build *library.Build + build *types.Build branch string want bool }{ @@ -165,7 +165,7 @@ func Test_ShouldAutoCancel(t *testing.T) { Pending: true, DefaultBranch: true, }, - build: &library.Build{ + build: &types.Build{ Event: &tagEvent, Branch: &branchPatch, }, @@ -179,7 +179,7 @@ func Test_ShouldAutoCancel(t *testing.T) { Pending: false, DefaultBranch: false, }, - build: &library.Build{ + build: &types.Build{ Event: &pushEvent, Branch: &branchPatch, }, @@ -193,7 +193,7 @@ func Test_ShouldAutoCancel(t *testing.T) { Pending: true, DefaultBranch: false, }, - build: &library.Build{ + build: &types.Build{ Event: &pushEvent, Branch: &branchPatch, }, @@ -207,7 +207,7 @@ func Test_ShouldAutoCancel(t *testing.T) { Pending: true, DefaultBranch: true, }, - build: &library.Build{ + build: &types.Build{ Event: &pushEvent, Branch: &branchDev, }, @@ -221,7 +221,7 @@ func Test_ShouldAutoCancel(t *testing.T) { Pending: true, DefaultBranch: false, }, - build: &library.Build{ + build: &types.Build{ Event: &pushEvent, Branch: &branchDev, }, @@ -235,7 +235,7 @@ func Test_ShouldAutoCancel(t *testing.T) { Pending: true, DefaultBranch: false, }, - build: &library.Build{ + build: &types.Build{ Event: &pullEvent, Branch: &branchDev, EventAction: &actionSync, @@ -250,7 +250,7 @@ func Test_ShouldAutoCancel(t *testing.T) { Pending: true, DefaultBranch: false, }, - build: &library.Build{ + build: &types.Build{ Event: &pullEvent, Branch: &branchDev, EventAction: &actionOpened, @@ -265,7 +265,7 @@ func Test_ShouldAutoCancel(t *testing.T) { Pending: false, DefaultBranch: false, }, - build: &library.Build{ + build: &types.Build{ Event: &pullEvent, Branch: &branchDev, EventAction: &actionOpened, diff --git a/api/build/cancel.go b/api/build/cancel.go index ad0ea30e7..afad5d0e0 100644 --- a/api/build/cancel.go +++ b/api/build/cancel.go @@ -8,7 +8,6 @@ import ( "fmt" "io" "net/http" - "strings" "time" "github.com/gin-gonic/gin" @@ -105,7 +104,7 @@ func CancelBuild(c *gin.Context) { for _, executor := range e { // check each executor on the worker running the build to see if it's running the build we want to cancel - if strings.EqualFold(executor.Repo.GetFullName(), r.GetFullName()) && *executor.GetBuild().Number == b.GetNumber() { + if executor.Build.GetID() == b.GetID() { // prepare the request to the worker client := http.DefaultClient client.Timeout = 30 * time.Second diff --git a/api/build/clean.go b/api/build/clean.go index 645b0bef3..235efc989 100644 --- a/api/build/clean.go +++ b/api/build/clean.go @@ -9,6 +9,7 @@ import ( "github.com/sirupsen/logrus" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" @@ -18,7 +19,7 @@ import ( // without execution. This will kill all resources, // like steps and services, for the build in the // configured backend. -func CleanBuild(ctx context.Context, database database.Interface, b *library.Build, services []*library.Service, steps []*library.Step, e error) { +func CleanBuild(ctx context.Context, database database.Interface, b *types.Build, services []*library.Service, steps []*library.Step, e error) { // update fields in build object b.SetError(fmt.Sprintf("unable to publish to queue: %s", e.Error())) b.SetStatus(constants.StatusError) diff --git a/api/build/compile_publish.go b/api/build/compile_publish.go index cc6d121e4..29f2cdac2 100644 --- a/api/build/compile_publish.go +++ b/api/build/compile_publish.go @@ -27,8 +27,7 @@ import ( // CompileAndPublishConfig is a struct that contains information for the CompileAndPublish function. type CompileAndPublishConfig struct { - Build *library.Build - Repo *types.Repo + Build *types.Build Metadata *internal.Metadata BaseErr string Source string @@ -50,11 +49,11 @@ func CompileAndPublish( compiler compiler.Engine, queue queue.Service, ) (*pipeline.Build, *models.Item, int, error) { - logrus.Debugf("generating queue items for build %s/%d", cfg.Repo.GetFullName(), cfg.Build.GetNumber()) + logrus.Debugf("generating queue items for build %s/%d", cfg.Build.GetRepo().GetFullName(), cfg.Build.GetNumber()) // assign variables from form for readibility - r := cfg.Repo - u := cfg.Repo.GetOwner() + r := cfg.Build.GetRepo() + u := cfg.Build.GetRepo().GetOwner() b := cfg.Build baseErr := cfg.BaseErr @@ -410,12 +409,12 @@ func CompileAndPublish( return nil, nil, http.StatusInternalServerError, retErr } - return p, models.ToItem(b, repo), http.StatusCreated, nil + return p, models.ToItem(b), http.StatusCreated, nil } // getPRNumberFromBuild is a helper function to // extract the pull request number from a Build. -func getPRNumberFromBuild(b *library.Build) (int, error) { +func getPRNumberFromBuild(b *types.Build) (int, error) { // parse out pull request number from base ref // // pattern: refs/pull/1/head diff --git a/api/build/create.go b/api/build/create.go index dc8c81149..f5782d331 100644 --- a/api/build/create.go +++ b/api/build/create.go @@ -9,6 +9,7 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/compiler" "github.com/go-vela/server/database" "github.com/go-vela/server/internal" @@ -18,7 +19,6 @@ import ( "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/scm" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" ) // swagger:operation POST /api/v1/repos/{org}/{repo}/builds builds CreateBuild @@ -99,7 +99,7 @@ func CreateBuild(c *gin.Context) { logger.Infof("creating new build for repo %s", r.GetFullName()) // capture body from API request - input := new(library.Build) + input := new(types.Build) err := c.Bind(input) if err != nil { @@ -110,6 +110,8 @@ func CreateBuild(c *gin.Context) { return } + input.SetRepo(r) + // verify the build has a valid event and the repo allows that event type if !r.GetAllowEvents().Allowed(input.GetEvent(), input.GetEventAction()) { retErr := fmt.Errorf("unable to create new build: %s does not have %s events enabled", r.GetFullName(), input.GetEvent()) @@ -122,7 +124,6 @@ func CreateBuild(c *gin.Context) { // create config config := CompileAndPublishConfig{ Build: input, - Repo: r, Metadata: m, BaseErr: "unable to create build", Source: "create", diff --git a/api/build/enqueue.go b/api/build/enqueue.go index cbc2054b5..297a974f5 100644 --- a/api/build/enqueue.go +++ b/api/build/enqueue.go @@ -16,11 +16,11 @@ import ( // Enqueue is a helper function that pushes a queue item (build, repo, user) to the queue. func Enqueue(ctx context.Context, queue queue.Service, db database.Interface, item *models.Item, route string) { - logrus.Infof("Converting queue item to json for build %d for %s", item.Build.GetNumber(), item.Repo.GetFullName()) + logrus.Infof("Converting queue item to json for build %d for %s", item.Build.GetNumber(), item.Build.GetRepo().GetFullName()) byteItem, err := json.Marshal(item) if err != nil { - logrus.Errorf("Failed to convert item to json for build %d for %s: %v", item.Build.GetNumber(), item.Repo.GetFullName(), err) + logrus.Errorf("Failed to convert item to json for build %d for %s: %v", item.Build.GetNumber(), item.Build.GetRepo().GetFullName(), err) // error out the build CleanBuild(ctx, db, item.Build, nil, nil, err) @@ -28,16 +28,16 @@ func Enqueue(ctx context.Context, queue queue.Service, db database.Interface, it return } - logrus.Infof("Pushing item for build %d for %s to queue route %s", item.Build.GetNumber(), item.Repo.GetFullName(), route) + logrus.Infof("Pushing item for build %d for %s to queue route %s", item.Build.GetNumber(), item.Build.GetRepo().GetFullName(), route) // push item on to the queue err = queue.Push(context.Background(), route, byteItem) if err != nil { - logrus.Errorf("Retrying; Failed to publish build %d for %s: %v", item.Build.GetNumber(), item.Repo.GetFullName(), err) + logrus.Errorf("Retrying; Failed to publish build %d for %s: %v", item.Build.GetNumber(), item.Build.GetRepo().GetFullName(), err) err = queue.Push(context.Background(), route, byteItem) if err != nil { - logrus.Errorf("Failed to publish build %d for %s: %v", item.Build.GetNumber(), item.Repo.GetFullName(), err) + logrus.Errorf("Failed to publish build %d for %s: %v", item.Build.GetNumber(), item.Build.GetRepo().GetFullName(), err) // error out the build CleanBuild(ctx, db, item.Build, nil, nil, err) @@ -52,6 +52,6 @@ func Enqueue(ctx context.Context, queue queue.Service, db database.Interface, it // update the build in the db to reflect the time it was enqueued _, err = db.UpdateBuild(ctx, item.Build) if err != nil { - logrus.Errorf("Failed to update build %d during publish to queue for %s: %v", item.Build.GetNumber(), item.Repo.GetFullName(), err) + logrus.Errorf("Failed to update build %d during publish to queue for %s: %v", item.Build.GetNumber(), item.Build.GetRepo().GetFullName(), err) } } diff --git a/api/build/executable.go b/api/build/executable.go index b855ee7bc..324984b10 100644 --- a/api/build/executable.go +++ b/api/build/executable.go @@ -11,6 +11,7 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/build" "github.com/go-vela/server/router/middleware/claims" @@ -99,7 +100,7 @@ func GetBuildExecutable(c *gin.Context) { // PublishBuildExecutable marshals a pipeline.Build into bytes and pushes that data to the build_executables table to be // requested by a worker whenever the build has been picked up. -func PublishBuildExecutable(ctx context.Context, db database.Interface, p *pipeline.Build, b *library.Build) error { +func PublishBuildExecutable(ctx context.Context, db database.Interface, p *pipeline.Build, b *types.Build) error { // marshal pipeline build into byte data to add to the build executable object byteExecutable, err := json.Marshal(p) if err != nil { diff --git a/api/build/get_id.go b/api/build/get_id.go index b53827c47..d0a72191d 100644 --- a/api/build/get_id.go +++ b/api/build/get_id.go @@ -10,12 +10,10 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" - "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/scm" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" ) // swagger:operation GET /api/v1/search/builds/{id} builds GetBuildByID @@ -50,12 +48,6 @@ import ( // GetBuildByID represents the API handler to capture a // build by its id from the configured backend. func GetBuildByID(c *gin.Context) { - // Variables that will hold the library types of the build and repo - var ( - b *library.Build - r *types.Repo - ) - // Capture user from middleware u := user.Retrieve(c) ctx := c.Request.Context() @@ -80,7 +72,7 @@ func GetBuildByID(c *gin.Context) { }).Infof("reading build %d", id) // Get build from database - b, err = database.FromContext(c).GetBuild(ctx, id) + b, err := database.FromContext(c).GetBuild(ctx, id) if err != nil { retErr := fmt.Errorf("unable to get build: %w", err) @@ -89,21 +81,11 @@ func GetBuildByID(c *gin.Context) { return } - // Get repo from database using repo ID field from build - r, err = database.FromContext(c).GetRepo(ctx, b.GetRepoID()) - if err != nil { - retErr := fmt.Errorf("unable to get repo: %w", err) - - util.HandleError(c, http.StatusInternalServerError, retErr) - - return - } - // Capture user access from SCM. We do this in order to ensure user has access and is not // just retrieving any build using a random id number. - perm, err := scm.FromContext(c).RepoAccess(ctx, u.GetName(), u.GetToken(), r.GetOrg(), r.GetName()) + perm, err := scm.FromContext(c).RepoAccess(ctx, u.GetName(), u.GetToken(), b.GetRepo().GetOrg(), b.GetRepo().GetName()) if err != nil { - logrus.Errorf("unable to get user %s access level for repo %s", u.GetName(), r.GetFullName()) + logrus.Errorf("unable to get user %s access level for repo %s", u.GetName(), b.GetRepo().GetFullName()) } // Ensure that user has at least read access to repo to return the build diff --git a/api/build/list_org.go b/api/build/list_org.go index ed2c4e929..a8e491a47 100644 --- a/api/build/list_org.go +++ b/api/build/list_org.go @@ -11,13 +11,13 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/server/api" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/scm" "github.com/go-vela/server/util" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) // swagger:operation GET /api/v1/repos/{org}/builds builds ListBuildsForOrg @@ -102,7 +102,7 @@ func ListBuildsForOrg(c *gin.Context) { // variables that will hold the build list, build list filters and total count var ( filters = map[string]interface{}{} - b []*library.Build + b []*types.Build t int64 ) diff --git a/api/build/list_repo.go b/api/build/list_repo.go index e8ed29845..9c3fca345 100644 --- a/api/build/list_repo.go +++ b/api/build/list_repo.go @@ -12,13 +12,13 @@ import ( "github.com/sirupsen/logrus" "github.com/go-vela/server/api" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/util" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) // swagger:operation GET /api/v1/repos/{org}/{repo}/builds builds ListBuildsForRepo @@ -122,7 +122,7 @@ func ListBuildsForRepo(c *gin.Context) { // variables that will hold the build list, build list filters and total count var ( filters = map[string]interface{}{} - b []*library.Build + b []*types.Build t int64 ) diff --git a/api/build/plan.go b/api/build/plan.go index d34a776ff..49e700d52 100644 --- a/api/build/plan.go +++ b/api/build/plan.go @@ -12,7 +12,6 @@ import ( "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/scm" - "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" ) @@ -21,7 +20,7 @@ import ( // and services, for the build in the configured backend. // TODO: // - return build and error. -func PlanBuild(ctx context.Context, database database.Interface, scm scm.Service, p *pipeline.Build, b *library.Build, r *types.Repo) error { +func PlanBuild(ctx context.Context, database database.Interface, scm scm.Service, p *pipeline.Build, b *types.Build, r *types.Repo) error { // update fields in build object b.SetCreated(time.Now().UTC().Unix()) @@ -51,7 +50,7 @@ func PlanBuild(ctx context.Context, database database.Interface, scm scm.Service } // plan all steps for the build - steps, err := step.PlanSteps(ctx, database, scm, p, b, r) + steps, err := step.PlanSteps(ctx, database, scm, p, b) if err != nil { // clean up the objects from the pipeline in the database CleanBuild(ctx, database, b, services, steps, err) diff --git a/api/build/restart.go b/api/build/restart.go index 51c1bc0ff..2569a4915 100644 --- a/api/build/restart.go +++ b/api/build/restart.go @@ -121,7 +121,6 @@ func RestartBuild(c *gin.Context) { // restart form config := CompileAndPublishConfig{ Build: b, - Repo: r, Metadata: m, BaseErr: "unable to restart build", Source: "restart", diff --git a/api/build/update.go b/api/build/update.go index be3f0cdec..e1b64b423 100644 --- a/api/build/update.go +++ b/api/build/update.go @@ -9,6 +9,7 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/build" "github.com/go-vela/server/router/middleware/claims" @@ -88,7 +89,7 @@ func UpdateBuild(c *gin.Context) { }).Infof("updating build %s", entry) // capture body from API request - input := new(library.Build) + input := new(types.Build) err := c.Bind(input) if err != nil { @@ -178,7 +179,7 @@ func UpdateBuild(c *gin.Context) { } // UpdateComponentStatuses updates all components (steps and services) for a build to a given status. -func UpdateComponentStatuses(c *gin.Context, b *library.Build, status string) error { +func UpdateComponentStatuses(c *gin.Context, b *types.Build, status string) error { ctx := c.Request.Context() // retrieve the steps for the build from the step table diff --git a/api/service/plan.go b/api/service/plan.go index 790c9b538..05673f05e 100644 --- a/api/service/plan.go +++ b/api/service/plan.go @@ -7,6 +7,7 @@ import ( "fmt" "time" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/types/constants" "github.com/go-vela/types/library" @@ -16,7 +17,7 @@ import ( // PlanServices is a helper function to plan all services // in the build for execution. This creates the services // for the build in the configured backend. -func PlanServices(ctx context.Context, database database.Interface, p *pipeline.Build, b *library.Build) ([]*library.Service, error) { +func PlanServices(ctx context.Context, database database.Interface, p *pipeline.Build, b *types.Build) ([]*library.Service, error) { // variable to store planned services services := []*library.Service{} @@ -25,7 +26,7 @@ func PlanServices(ctx context.Context, database database.Interface, p *pipeline. // create the service object s := new(library.Service) s.SetBuildID(b.GetID()) - s.SetRepoID(b.GetRepoID()) + s.SetRepoID(b.GetRepo().GetID()) s.SetName(service.Name) s.SetImage(service.Image) s.SetNumber(service.Number) @@ -50,7 +51,7 @@ func PlanServices(ctx context.Context, database database.Interface, p *pipeline. l := new(library.Log) l.SetServiceID(s.GetID()) l.SetBuildID(b.GetID()) - l.SetRepoID(b.GetRepoID()) + l.SetRepoID(b.GetRepo().GetID()) l.SetData([]byte{}) // send API call to create the service logs diff --git a/api/step/plan.go b/api/step/plan.go index 7e493aab6..f685170a3 100644 --- a/api/step/plan.go +++ b/api/step/plan.go @@ -20,7 +20,7 @@ import ( // PlanSteps is a helper function to plan all steps // in the build for execution. This creates the steps // for the build in the configured backend. -func PlanSteps(ctx context.Context, database database.Interface, scm scm.Service, p *pipeline.Build, b *library.Build, repo *types.Repo) ([]*library.Step, error) { +func PlanSteps(ctx context.Context, database database.Interface, scm scm.Service, p *pipeline.Build, b *types.Build) ([]*library.Step, error) { // variable to store planned steps steps := []*library.Step{} @@ -29,7 +29,7 @@ func PlanSteps(ctx context.Context, database database.Interface, scm scm.Service // iterate through all steps for each pipeline stage for _, step := range stage.Steps { // create the step object - s, err := planStep(ctx, database, scm, b, step, repo, stage.Name) + s, err := planStep(ctx, database, scm, b, step, stage.Name) if err != nil { return steps, err } @@ -40,7 +40,7 @@ func PlanSteps(ctx context.Context, database database.Interface, scm scm.Service // iterate through all pipeline steps for _, step := range p.Steps { - s, err := planStep(ctx, database, scm, b, step, repo, "") + s, err := planStep(ctx, database, scm, b, step, "") if err != nil { return steps, err } @@ -51,11 +51,11 @@ func PlanSteps(ctx context.Context, database database.Interface, scm scm.Service return steps, nil } -func planStep(ctx context.Context, database database.Interface, scm scm.Service, b *library.Build, c *pipeline.Container, repo *types.Repo, stage string) (*library.Step, error) { +func planStep(ctx context.Context, database database.Interface, scm scm.Service, b *types.Build, c *pipeline.Container, stage string) (*library.Step, error) { // create the step object s := new(library.Step) s.SetBuildID(b.GetID()) - s.SetRepoID(b.GetRepoID()) + s.SetRepoID(b.GetRepo().GetID()) s.SetNumber(c.Number) s.SetName(c.Name) s.SetImage(c.Image) @@ -82,7 +82,7 @@ func planStep(ctx context.Context, database database.Interface, scm scm.Service, l := new(library.Log) l.SetStepID(s.GetID()) l.SetBuildID(b.GetID()) - l.SetRepoID(b.GetRepoID()) + l.SetRepoID(b.GetRepo().GetID()) l.SetData([]byte{}) // send API call to create the step logs @@ -93,7 +93,7 @@ func planStep(ctx context.Context, database database.Interface, scm scm.Service, if len(s.GetReportAs()) > 0 { // send API call to set the status on the commit - err = scm.StepStatus(ctx, repo.GetOwner(), b, s, repo.GetOrg(), repo.GetName()) + err = scm.StepStatus(ctx, b.GetRepo().GetOwner(), b, s, b.GetRepo().GetOrg(), b.GetRepo().GetName()) if err != nil { logrus.Errorf("unable to set commit status for build: %v", err) } diff --git a/api/types/build.go b/api/types/build.go new file mode 100644 index 000000000..231e8b80b --- /dev/null +++ b/api/types/build.go @@ -0,0 +1,1218 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "fmt" + "strings" + "time" + + "github.com/go-vela/types/constants" + "github.com/go-vela/types/library" + "github.com/go-vela/types/raw" +) + +// Build is the API types representation of a build for a pipeline. +// +// swagger:model Build +type Build struct { + ID *int64 `json:"id,omitempty"` + Repo *Repo `json:"repo,omitempty"` + PipelineID *int64 `json:"pipeline_id,omitempty"` + Number *int `json:"number,omitempty"` + Parent *int `json:"parent,omitempty"` + Event *string `json:"event,omitempty"` + EventAction *string `json:"event_action,omitempty"` + Status *string `json:"status,omitempty"` + Error *string `json:"error,omitempty"` + Enqueued *int64 `json:"enqueued,omitempty"` + Created *int64 `json:"created,omitempty"` + Started *int64 `json:"started,omitempty"` + Finished *int64 `json:"finished,omitempty"` + Deploy *string `json:"deploy,omitempty"` + DeployNumber *int64 `json:"deploy_number,omitempty"` + DeployPayload *raw.StringSliceMap `json:"deploy_payload,omitempty"` + Clone *string `json:"clone,omitempty"` + Source *string `json:"source,omitempty"` + Title *string `json:"title,omitempty"` + Message *string `json:"message,omitempty"` + Commit *string `json:"commit,omitempty"` + Sender *string `json:"sender,omitempty"` + Author *string `json:"author,omitempty"` + Email *string `json:"email,omitempty"` + Link *string `json:"link,omitempty"` + Branch *string `json:"branch,omitempty"` + Ref *string `json:"ref,omitempty"` + BaseRef *string `json:"base_ref,omitempty"` + HeadRef *string `json:"head_ref,omitempty"` + Host *string `json:"host,omitempty"` + Runtime *string `json:"runtime,omitempty"` + Distribution *string `json:"distribution,omitempty"` + ApprovedAt *int64 `json:"approved_at,omitempty"` + ApprovedBy *string `json:"approved_by,omitempty"` +} + +// Duration calculates and returns the total amount of +// time the build ran for in a human-readable format. +func (b *Build) Duration() string { + // check if the build doesn't have a started timestamp + if b.GetStarted() == 0 { + return "..." + } + + // capture started unix timestamp from the build + started := time.Unix(b.GetStarted(), 0) + + // check if the build doesn't have a finished timestamp + if b.GetFinished() == 0 { + // return the duration in a human-readable form by + // subtracting the build started time from the + // current time rounded to the nearest second + return time.Since(started).Round(time.Second).String() + } + + // capture finished unix timestamp from the build + finished := time.Unix(b.GetFinished(), 0) + + // calculate the duration by subtracting the build + // started time from the build finished time + duration := finished.Sub(started) + + // return the duration in a human-readable form + return duration.String() +} + +// Environment returns a list of environment variables +// provided from the fields of the Build type. +func (b *Build) Environment(workspace, channel string) map[string]string { + envs := map[string]string{ + "VELA_BUILD_APPROVED_AT": ToString(b.GetApprovedAt()), + "VELA_BUILD_APPROVED_BY": ToString(b.GetApprovedBy()), + "VELA_BUILD_AUTHOR": ToString(b.GetAuthor()), + "VELA_BUILD_AUTHOR_EMAIL": ToString(b.GetEmail()), + "VELA_BUILD_BASE_REF": ToString(b.GetBaseRef()), + "VELA_BUILD_BRANCH": ToString(b.GetBranch()), + "VELA_BUILD_CHANNEL": ToString(channel), + "VELA_BUILD_CLONE": ToString(b.GetClone()), + "VELA_BUILD_COMMIT": ToString(b.GetCommit()), + "VELA_BUILD_CREATED": ToString(b.GetCreated()), + "VELA_BUILD_DISTRIBUTION": ToString(b.GetDistribution()), + "VELA_BUILD_ENQUEUED": ToString(b.GetEnqueued()), + "VELA_BUILD_EVENT": ToString(b.GetEvent()), + "VELA_BUILD_EVENT_ACTION": ToString(b.GetEventAction()), + "VELA_BUILD_HOST": ToString(b.GetHost()), + "VELA_BUILD_LINK": ToString(b.GetLink()), + "VELA_BUILD_MESSAGE": ToString(b.GetMessage()), + "VELA_BUILD_NUMBER": ToString(b.GetNumber()), + "VELA_BUILD_PARENT": ToString(b.GetParent()), + "VELA_BUILD_REF": ToString(b.GetRef()), + "VELA_BUILD_RUNTIME": ToString(b.GetRuntime()), + "VELA_BUILD_SENDER": ToString(b.GetSender()), + "VELA_BUILD_STARTED": ToString(b.GetStarted()), + "VELA_BUILD_SOURCE": ToString(b.GetSource()), + "VELA_BUILD_STATUS": ToString(b.GetStatus()), + "VELA_BUILD_TITLE": ToString(b.GetTitle()), + "VELA_BUILD_WORKSPACE": ToString(workspace), + + // deprecated environment variables + "BUILD_AUTHOR": ToString(b.GetAuthor()), + "BUILD_AUTHOR_EMAIL": ToString(b.GetEmail()), + "BUILD_BASE_REF": ToString(b.GetBaseRef()), + "BUILD_BRANCH": ToString(b.GetBranch()), + "BUILD_CHANNEL": ToString(channel), + "BUILD_CLONE": ToString(b.GetClone()), + "BUILD_COMMIT": ToString(b.GetCommit()), + "BUILD_CREATED": ToString(b.GetCreated()), + "BUILD_ENQUEUED": ToString(b.GetEnqueued()), + "BUILD_EVENT": ToString(b.GetEvent()), + "BUILD_HOST": ToString(b.GetHost()), + "BUILD_LINK": ToString(b.GetLink()), + "BUILD_MESSAGE": ToString(b.GetMessage()), + "BUILD_NUMBER": ToString(b.GetNumber()), + "BUILD_PARENT": ToString(b.GetParent()), + "BUILD_REF": ToString(b.GetRef()), + "BUILD_SENDER": ToString(b.GetSender()), + "BUILD_STARTED": ToString(b.GetStarted()), + "BUILD_SOURCE": ToString(b.GetSource()), + "BUILD_STATUS": ToString(b.GetStatus()), + "BUILD_TITLE": ToString(b.GetTitle()), + "BUILD_WORKSPACE": ToString(workspace), + } + + // check if the Build event is comment + if strings.EqualFold(b.GetEvent(), constants.EventComment) { + // capture the pull request number + number := ToString(strings.SplitN(b.GetRef(), "/", 4)[2]) + + // add the pull request number to the list + envs["BUILD_PULL_REQUEST_NUMBER"] = number + envs["VELA_BUILD_PULL_REQUEST"] = number + envs["VELA_PULL_REQUEST"] = number + envs["VELA_PULL_REQUEST_SOURCE"] = b.GetHeadRef() + envs["VELA_PULL_REQUEST_TARGET"] = b.GetBaseRef() + } + + // check if the Build event is deployment + if strings.EqualFold(b.GetEvent(), constants.EventDeploy) { + // capture the deployment target + target := ToString(b.GetDeploy()) + + // add the deployment target to the list + envs["VELA_BUILD_TARGET"] = target + envs["VELA_DEPLOYMENT"] = target + envs["BUILD_TARGET"] = target + envs["VELA_DEPLOYMENT_NUMBER"] = ToString(b.GetDeployNumber()) + + // handle when deployment event is for a tag + if strings.HasPrefix(b.GetRef(), "refs/tags/") { + // capture the tag reference + tag := ToString(strings.SplitN(b.GetRef(), "refs/tags/", 2)[1]) + + // add the tag reference to the list + envs["BUILD_TAG"] = tag + envs["VELA_BUILD_TAG"] = tag + } + + // add payload data to the list + for key, value := range b.GetDeployPayload() { + envs[fmt.Sprintf("DEPLOYMENT_PARAMETER_%s", strings.ToUpper(key))] = value + } + } + + // check if the Build event is pull_request + if strings.EqualFold(b.GetEvent(), constants.EventPull) { + // capture the pull request number + number := ToString(strings.SplitN(b.GetRef(), "/", 4)[2]) + + // add the pull request number to the list + envs["BUILD_PULL_REQUEST_NUMBER"] = number + envs["VELA_BUILD_PULL_REQUEST"] = number + envs["VELA_PULL_REQUEST"] = number + envs["VELA_PULL_REQUEST_SOURCE"] = b.GetHeadRef() + envs["VELA_PULL_REQUEST_TARGET"] = b.GetBaseRef() + } + + // check if the Build event is tag + if strings.EqualFold(b.GetEvent(), constants.EventTag) { + // capture the tag reference + tag := ToString(strings.SplitN(b.GetRef(), "refs/tags/", 2)[1]) + + // add the tag reference to the list + envs["BUILD_TAG"] = tag + envs["VELA_BUILD_TAG"] = tag + } + + // check if the Build event is delete:tag + if strings.EqualFold(b.GetEvent(), constants.EventDelete) && strings.EqualFold(b.GetEventAction(), constants.ActionTag) { + // capture the tag reference, which has been stored in the Branch variable due to issues that arose + // when the Ref is set to the deleted tag + tag := b.GetBranch() + + // add the tag reference to the list + envs["BUILD_TAG"] = tag + envs["VELA_BUILD_TAG"] = tag + } + + return envs +} + +// GetID returns the ID field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetID() int64 { + // return zero value if Build type or ID field is nil + if b == nil || b.ID == nil { + return 0 + } + + return *b.ID +} + +// GetRepo returns the Repo field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetRepo() *Repo { + // return zero value if Build type or Repo field is nil + if b == nil || b.Repo == nil { + return new(Repo) + } + + return b.Repo +} + +// GetPipelineID returns the PipelineID field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetPipelineID() int64 { + // return zero value if Build type or PipelineID field is nil + if b == nil || b.PipelineID == nil { + return 0 + } + + return *b.PipelineID +} + +// GetNumber returns the Number field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetNumber() int { + // return zero value if Build type or Number field is nil + if b == nil || b.Number == nil { + return 0 + } + + return *b.Number +} + +// GetParent returns the Parent field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetParent() int { + // return zero value if Build type or Parent field is nil + if b == nil || b.Parent == nil { + return 0 + } + + return *b.Parent +} + +// GetEvent returns the Event field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetEvent() string { + // return zero value if Build type or Event field is nil + if b == nil || b.Event == nil { + return "" + } + + return *b.Event +} + +// GetEventAction returns the EventAction field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetEventAction() string { + // return zero value if Build type or EventAction field is nil + if b == nil || b.EventAction == nil { + return "" + } + + return *b.EventAction +} + +// GetStatus returns the Status field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetStatus() string { + // return zero value if Build type or Status field is nil + if b == nil || b.Status == nil { + return "" + } + + return *b.Status +} + +// GetError returns the Error field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetError() string { + // return zero value if Build type or Error field is nil + if b == nil || b.Error == nil { + return "" + } + + return *b.Error +} + +// GetEnqueued returns the Enqueued field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetEnqueued() int64 { + // return zero value if Build type or Enqueued field is nil + if b == nil || b.Enqueued == nil { + return 0 + } + + return *b.Enqueued +} + +// GetCreated returns the Created field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetCreated() int64 { + // return zero value if Build type or Created field is nil + if b == nil || b.Created == nil { + return 0 + } + + return *b.Created +} + +// GetStarted returns the Started field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetStarted() int64 { + // return zero value if Build type or Started field is nil + if b == nil || b.Started == nil { + return 0 + } + + return *b.Started +} + +// GetFinished returns the Finished field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetFinished() int64 { + // return zero value if Build type or Finished field is nil + if b == nil || b.Finished == nil { + return 0 + } + + return *b.Finished +} + +// GetDeploy returns the Deploy field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetDeploy() string { + // return zero value if Build type or Deploy field is nil + if b == nil || b.Deploy == nil { + return "" + } + + return *b.Deploy +} + +// GetDeployNumber returns the DeployNumber field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetDeployNumber() int64 { + // return zero value if Build type or Deploy field is nil + if b == nil || b.DeployNumber == nil { + return 0 + } + + return *b.DeployNumber +} + +// GetDeployPayload returns the DeployPayload field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetDeployPayload() raw.StringSliceMap { + // return zero value if Build type or Deploy field is nil + if b == nil || b.DeployPayload == nil { + return raw.StringSliceMap{} + } + + return *b.DeployPayload +} + +// GetClone returns the Clone field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetClone() string { + // return zero value if Build type or Clone field is nil + if b == nil || b.Clone == nil { + return "" + } + + return *b.Clone +} + +// GetSource returns the Source field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetSource() string { + // return zero value if Build type or Source field is nil + if b == nil || b.Source == nil { + return "" + } + + return *b.Source +} + +// GetTitle returns the Title field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetTitle() string { + // return zero value if Build type or Title field is nil + if b == nil || b.Title == nil { + return "" + } + + return *b.Title +} + +// GetMessage returns the Message field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetMessage() string { + // return zero value if Build type or Message field is nil + if b == nil || b.Message == nil { + return "" + } + + return *b.Message +} + +// GetCommit returns the Commit field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetCommit() string { + // return zero value if Build type or Commit field is nil + if b == nil || b.Commit == nil { + return "" + } + + return *b.Commit +} + +// GetSender returns the Sender field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetSender() string { + // return zero value if Build type or Sender field is nil + if b == nil || b.Sender == nil { + return "" + } + + return *b.Sender +} + +// GetAuthor returns the Author field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetAuthor() string { + // return zero value if Build type or Author field is nil + if b == nil || b.Author == nil { + return "" + } + + return *b.Author +} + +// GetEmail returns the Email field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetEmail() string { + // return zero value if Build type or Email field is nil + if b == nil || b.Email == nil { + return "" + } + + return *b.Email +} + +// GetLink returns the Link field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetLink() string { + // return zero value if Build type or Link field is nil + if b == nil || b.Link == nil { + return "" + } + + return *b.Link +} + +// GetBranch returns the Branch field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetBranch() string { + // return zero value if Build type or Branch field is nil + if b == nil || b.Branch == nil { + return "" + } + + return *b.Branch +} + +// GetRef returns the Ref field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetRef() string { + // return zero value if Build type or Ref field is nil + if b == nil || b.Ref == nil { + return "" + } + + return *b.Ref +} + +// GetBaseRef returns the BaseRef field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetBaseRef() string { + // return zero value if Build type or BaseRef field is nil + if b == nil || b.BaseRef == nil { + return "" + } + + return *b.BaseRef +} + +// GetHeadRef returns the HeadRef field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetHeadRef() string { + // return zero value if Build type or HeadRef field is nil + if b == nil || b.HeadRef == nil { + return "" + } + + return *b.HeadRef +} + +// GetHost returns the Host field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetHost() string { + // return zero value if Build type or Host field is nil + if b == nil || b.Host == nil { + return "" + } + + return *b.Host +} + +// GetRuntime returns the Runtime field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetRuntime() string { + // return zero value if Build type or Runtime field is nil + if b == nil || b.Runtime == nil { + return "" + } + + return *b.Runtime +} + +// GetDistribution returns the Distribution field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetDistribution() string { + // return zero value if Build type or Distribution field is nil + if b == nil || b.Distribution == nil { + return "" + } + + return *b.Distribution +} + +// GetApprovedAt returns the ApprovedAt field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetApprovedAt() int64 { + // return zero value if Build type or ApprovedAt field is nil + if b == nil || b.ApprovedAt == nil { + return 0 + } + + return *b.ApprovedAt +} + +// GetApprovedBy returns the ApprovedBy field. +// +// When the provided Build type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *Build) GetApprovedBy() string { + // return zero value if Build type or ApprovedBy field is nil + if b == nil || b.ApprovedBy == nil { + return "" + } + + return *b.ApprovedBy +} + +// SetID sets the ID field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetID(v int64) { + // return if Build type is nil + if b == nil { + return + } + + b.ID = &v +} + +// SetRepo sets the Repo field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetRepo(v *Repo) { + // return if Build type is nil + if b == nil { + return + } + + b.Repo = v +} + +// SetPipelineID sets the PipelineID field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetPipelineID(v int64) { + // return if Build type is nil + if b == nil { + return + } + + b.PipelineID = &v +} + +// SetNumber sets the Number field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetNumber(v int) { + // return if Build type is nil + if b == nil { + return + } + + b.Number = &v +} + +// SetParent sets the Parent field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetParent(v int) { + // return if Build type is nil + if b == nil { + return + } + + b.Parent = &v +} + +// SetEvent sets the Event field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetEvent(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Event = &v +} + +// SetEventAction sets the EventAction field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetEventAction(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.EventAction = &v +} + +// SetStatus sets the Status field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetStatus(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Status = &v +} + +// SetError sets the Error field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetError(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Error = &v +} + +// SetEnqueued sets the Enqueued field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetEnqueued(v int64) { + // return if Build type is nil + if b == nil { + return + } + + b.Enqueued = &v +} + +// SetCreated sets the Created field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetCreated(v int64) { + // return if Build type is nil + if b == nil { + return + } + + b.Created = &v +} + +// SetStarted sets the Started field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetStarted(v int64) { + // return if Build type is nil + if b == nil { + return + } + + b.Started = &v +} + +// SetFinished sets the Finished field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetFinished(v int64) { + // return if Build type is nil + if b == nil { + return + } + + b.Finished = &v +} + +// SetDeploy sets the Deploy field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetDeploy(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Deploy = &v +} + +// SetDeployNumber sets the DeployNumber field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetDeployNumber(v int64) { + // return if Build type is nil + if b == nil { + return + } + + b.DeployNumber = &v +} + +// SetDeployPayload sets the DeployPayload field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetDeployPayload(v raw.StringSliceMap) { + // return if Build type is nil + if b == nil { + return + } + + b.DeployPayload = &v +} + +// SetClone sets the Clone field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetClone(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Clone = &v +} + +// SetSource sets the Source field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetSource(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Source = &v +} + +// SetTitle sets the Title field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetTitle(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Title = &v +} + +// SetMessage sets the Message field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetMessage(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Message = &v +} + +// SetCommit sets the Commit field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetCommit(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Commit = &v +} + +// SetSender sets the Sender field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetSender(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Sender = &v +} + +// SetAuthor sets the Author field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetAuthor(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Author = &v +} + +// SetEmail sets the Email field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetEmail(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Email = &v +} + +// SetLink sets the Link field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetLink(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Link = &v +} + +// SetBranch sets the Branch field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetBranch(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Branch = &v +} + +// SetRef sets the Ref field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetRef(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Ref = &v +} + +// SetBaseRef sets the BaseRef field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetBaseRef(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.BaseRef = &v +} + +// SetHeadRef sets the HeadRef field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetHeadRef(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.HeadRef = &v +} + +// SetHost sets the Host field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetHost(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Host = &v +} + +// SetRuntime sets the Runtime field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetRuntime(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Runtime = &v +} + +// SetDistribution sets the Distribution field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetDistribution(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.Distribution = &v +} + +// SetApprovedAt sets the ApprovedAt field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetApprovedAt(v int64) { + // return if Build type is nil + if b == nil { + return + } + + b.ApprovedAt = &v +} + +// SetApprovedBy sets the ApprovedBy field. +// +// When the provided Build type is nil, it +// will set nothing and immediately return. +func (b *Build) SetApprovedBy(v string) { + // return if Build type is nil + if b == nil { + return + } + + b.ApprovedBy = &v +} + +// String implements the Stringer interface for the Build type. +// +//nolint:dupl // this is duplicated in the test +func (b *Build) String() string { + return fmt.Sprintf(`{ + ApprovedAt: %d, + ApprovedBy: %s, + Author: %s, + BaseRef: %s, + Branch: %s, + Clone: %s, + Commit: %s, + Created: %d, + Deploy: %s, + DeployNumber: %d, + DeployPayload: %s, + Distribution: %s, + Email: %s, + Enqueued: %d, + Error: %s, + Event: %s, + EventAction: %s, + Finished: %d, + HeadRef: %s, + Host: %s, + ID: %d, + Link: %s, + Message: %s, + Number: %d, + Parent: %d, + PipelineID: %d, + Ref: %s, + Repo: %s, + Runtime: %s, + Sender: %s, + Source: %s, + Started: %d, + Status: %s, + Title: %s, +}`, + b.GetApprovedAt(), + b.GetApprovedBy(), + b.GetAuthor(), + b.GetBaseRef(), + b.GetBranch(), + b.GetClone(), + b.GetCommit(), + b.GetCreated(), + b.GetDeploy(), + b.GetDeployNumber(), + b.GetDeployPayload(), + b.GetDistribution(), + b.GetEmail(), + b.GetEnqueued(), + b.GetError(), + b.GetEvent(), + b.GetEventAction(), + b.GetFinished(), + b.GetHeadRef(), + b.GetHost(), + b.GetID(), + b.GetLink(), + b.GetMessage(), + b.GetNumber(), + b.GetParent(), + b.GetPipelineID(), + b.GetRef(), + b.GetRepo().GetFullName(), + b.GetRuntime(), + b.GetSender(), + b.GetSource(), + b.GetStarted(), + b.GetStatus(), + b.GetTitle(), + ) +} + +// TODO: remove this when Deployment is moved from types and uses Build type instead of library type. +func (b *Build) ToLibrary() *library.Build { + return &library.Build{ + ID: b.ID, + RepoID: b.GetRepo().ID, + PipelineID: b.PipelineID, + Number: b.Number, + Parent: b.Parent, + Event: b.Event, + EventAction: b.EventAction, + Status: b.Status, + Error: b.Error, + Enqueued: b.Enqueued, + Created: b.Created, + Started: b.Started, + Finished: b.Finished, + Deploy: b.Deploy, + DeployNumber: b.DeployNumber, + DeployPayload: b.DeployPayload, + Clone: b.Clone, + Source: b.Source, + Title: b.Title, + Message: b.Message, + Commit: b.Commit, + Sender: b.Sender, + Author: b.Author, + Email: b.Email, + Link: b.Link, + Branch: b.Branch, + Ref: b.Ref, + BaseRef: b.BaseRef, + HeadRef: b.HeadRef, + Host: b.Host, + Runtime: b.Runtime, + Distribution: b.Distribution, + ApprovedAt: b.ApprovedAt, + ApprovedBy: b.ApprovedBy, + } +} diff --git a/api/types/build_test.go b/api/types/build_test.go new file mode 100644 index 000000000..d70853bda --- /dev/null +++ b/api/types/build_test.go @@ -0,0 +1,928 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "fmt" + "reflect" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + + "github.com/go-vela/types/raw" +) + +func TestTypes_Build_Duration(t *testing.T) { + // setup types + unfinished := testBuild() + unfinished.SetFinished(0) + + // setup tests + tests := []struct { + build *Build + want string + }{ + { + build: testBuild(), + want: "1s", + }, + { + build: unfinished, + want: time.Since(time.Unix(unfinished.GetStarted(), 0)).Round(time.Second).String(), + }, + { + build: new(Build), + want: "...", + }, + } + + // run tests + for _, test := range tests { + got := test.build.Duration() + + if got != test.want { + t.Errorf("Duration is %v, want %v", got, test.want) + } + } +} + +func TestTypes_Build_Environment(t *testing.T) { + // setup types + _comment := testBuild() + _comment.SetEvent("comment") + _comment.SetEventAction("created") + _comment.SetRef("refs/pulls/1/head") + _comment.SetHeadRef("dev") + _comment.SetBaseRef("main") + + _deploy := testBuild() + _deploy.SetEvent("deployment") + _deploy.SetDeploy("production") + _deploy.SetDeployNumber(0) + _deploy.SetDeployPayload(map[string]string{ + "foo": "test1", + "bar": "test2", + }) + + _deployTag := testBuild() + _deployTag.SetRef("refs/tags/v0.1.0") + _deployTag.SetEvent("deployment") + _deployTag.SetDeploy("production") + _deployTag.SetDeployNumber(0) + _deployTag.SetDeployPayload(map[string]string{ + "foo": "test1", + "bar": "test2", + }) + + _pull := testBuild() + _pull.SetEvent("pull_request") + _pull.SetEventAction("opened") + _pull.SetRef("refs/pulls/1/head") + + _tag := testBuild() + _tag.SetEvent("tag") + _tag.SetRef("refs/tags/v0.1.0") + + // setup tests + tests := []struct { + build *Build + want map[string]string + }{ + { + build: testBuild(), + want: map[string]string{ + "VELA_BUILD_APPROVED_AT": "1563474076", + "VELA_BUILD_APPROVED_BY": "OctoCat", + "VELA_BUILD_AUTHOR": "OctoKitty", + "VELA_BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "VELA_BUILD_BASE_REF": "", + "VELA_BUILD_BRANCH": "main", + "VELA_BUILD_CHANNEL": "TODO", + "VELA_BUILD_CLONE": "https://github.com/github/octocat.git", + "VELA_BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_CREATED": "1563474076", + "VELA_BUILD_DISTRIBUTION": "linux", + "VELA_BUILD_ENQUEUED": "1563474077", + "VELA_BUILD_EVENT": "push", + "VELA_BUILD_EVENT_ACTION": "", + "VELA_BUILD_HOST": "example.company.com", + "VELA_BUILD_LINK": "https://example.company.com/github/octocat/1", + "VELA_BUILD_MESSAGE": "First commit...", + "VELA_BUILD_NUMBER": "1", + "VELA_BUILD_PARENT": "1", + "VELA_BUILD_REF": "refs/heads/main", + "VELA_BUILD_RUNTIME": "docker", + "VELA_BUILD_SENDER": "OctoKitty", + "VELA_BUILD_STARTED": "1563474078", + "VELA_BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_STATUS": "running", + "VELA_BUILD_TITLE": "push received from https://github.com/github/octocat", + "VELA_BUILD_WORKSPACE": "TODO", + "BUILD_AUTHOR": "OctoKitty", + "BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "BUILD_BASE_REF": "", + "BUILD_BRANCH": "main", + "BUILD_CHANNEL": "TODO", + "BUILD_CLONE": "https://github.com/github/octocat.git", + "BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_CREATED": "1563474076", + "BUILD_ENQUEUED": "1563474077", + "BUILD_EVENT": "push", + "BUILD_HOST": "example.company.com", + "BUILD_LINK": "https://example.company.com/github/octocat/1", + "BUILD_MESSAGE": "First commit...", + "BUILD_NUMBER": "1", + "BUILD_PARENT": "1", + "BUILD_REF": "refs/heads/main", + "BUILD_SENDER": "OctoKitty", + "BUILD_STARTED": "1563474078", + "BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_STATUS": "running", + "BUILD_TITLE": "push received from https://github.com/github/octocat", + "BUILD_WORKSPACE": "TODO", + }, + }, + { + build: _comment, + want: map[string]string{ + "VELA_BUILD_APPROVED_AT": "1563474076", + "VELA_BUILD_APPROVED_BY": "OctoCat", + "VELA_BUILD_AUTHOR": "OctoKitty", + "VELA_BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "VELA_BUILD_BASE_REF": "main", + "VELA_BUILD_BRANCH": "main", + "VELA_BUILD_CHANNEL": "TODO", + "VELA_BUILD_CLONE": "https://github.com/github/octocat.git", + "VELA_BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_CREATED": "1563474076", + "VELA_BUILD_DISTRIBUTION": "linux", + "VELA_BUILD_ENQUEUED": "1563474077", + "VELA_BUILD_EVENT": "comment", + "VELA_BUILD_EVENT_ACTION": "created", + "VELA_BUILD_HOST": "example.company.com", + "VELA_BUILD_LINK": "https://example.company.com/github/octocat/1", + "VELA_BUILD_MESSAGE": "First commit...", + "VELA_BUILD_NUMBER": "1", + "VELA_BUILD_PARENT": "1", + "VELA_BUILD_PULL_REQUEST": "1", + "VELA_BUILD_REF": "refs/pulls/1/head", + "VELA_BUILD_RUNTIME": "docker", + "VELA_BUILD_SENDER": "OctoKitty", + "VELA_BUILD_STARTED": "1563474078", + "VELA_BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_STATUS": "running", + "VELA_BUILD_TITLE": "push received from https://github.com/github/octocat", + "VELA_BUILD_WORKSPACE": "TODO", + "VELA_PULL_REQUEST": "1", + "VELA_PULL_REQUEST_SOURCE": "dev", + "VELA_PULL_REQUEST_TARGET": "main", + "BUILD_AUTHOR": "OctoKitty", + "BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "BUILD_BASE_REF": "main", + "BUILD_BRANCH": "main", + "BUILD_CHANNEL": "TODO", + "BUILD_CLONE": "https://github.com/github/octocat.git", + "BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_CREATED": "1563474076", + "BUILD_ENQUEUED": "1563474077", + "BUILD_EVENT": "comment", + "BUILD_HOST": "example.company.com", + "BUILD_LINK": "https://example.company.com/github/octocat/1", + "BUILD_MESSAGE": "First commit...", + "BUILD_NUMBER": "1", + "BUILD_PARENT": "1", + "BUILD_PULL_REQUEST_NUMBER": "1", + "BUILD_REF": "refs/pulls/1/head", + "BUILD_SENDER": "OctoKitty", + "BUILD_STARTED": "1563474078", + "BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_STATUS": "running", + "BUILD_TITLE": "push received from https://github.com/github/octocat", + "BUILD_WORKSPACE": "TODO", + }, + }, + { + build: _deploy, + want: map[string]string{ + "VELA_BUILD_APPROVED_AT": "1563474076", + "VELA_BUILD_APPROVED_BY": "OctoCat", + "VELA_BUILD_AUTHOR": "OctoKitty", + "VELA_BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "VELA_BUILD_BASE_REF": "", + "VELA_BUILD_BRANCH": "main", + "VELA_BUILD_CHANNEL": "TODO", + "VELA_BUILD_CLONE": "https://github.com/github/octocat.git", + "VELA_BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_CREATED": "1563474076", + "VELA_BUILD_DISTRIBUTION": "linux", + "VELA_BUILD_ENQUEUED": "1563474077", + "VELA_BUILD_EVENT": "deployment", + "VELA_BUILD_EVENT_ACTION": "", + "VELA_BUILD_HOST": "example.company.com", + "VELA_BUILD_LINK": "https://example.company.com/github/octocat/1", + "VELA_BUILD_MESSAGE": "First commit...", + "VELA_BUILD_NUMBER": "1", + "VELA_BUILD_PARENT": "1", + "VELA_BUILD_REF": "refs/heads/main", + "VELA_BUILD_RUNTIME": "docker", + "VELA_BUILD_SENDER": "OctoKitty", + "VELA_BUILD_STARTED": "1563474078", + "VELA_BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_STATUS": "running", + "VELA_BUILD_TARGET": "production", + "VELA_BUILD_TITLE": "push received from https://github.com/github/octocat", + "VELA_BUILD_WORKSPACE": "TODO", + "VELA_DEPLOYMENT": "production", + "VELA_DEPLOYMENT_NUMBER": "0", + "BUILD_TARGET": "production", + "BUILD_AUTHOR": "OctoKitty", + "BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "BUILD_BASE_REF": "", + "BUILD_BRANCH": "main", + "BUILD_CHANNEL": "TODO", + "BUILD_CLONE": "https://github.com/github/octocat.git", + "BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_CREATED": "1563474076", + "BUILD_ENQUEUED": "1563474077", + "BUILD_EVENT": "deployment", + "BUILD_HOST": "example.company.com", + "BUILD_LINK": "https://example.company.com/github/octocat/1", + "BUILD_MESSAGE": "First commit...", + "BUILD_NUMBER": "1", + "BUILD_PARENT": "1", + "BUILD_REF": "refs/heads/main", + "BUILD_SENDER": "OctoKitty", + "BUILD_STARTED": "1563474078", + "BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_STATUS": "running", + "BUILD_TITLE": "push received from https://github.com/github/octocat", + "BUILD_WORKSPACE": "TODO", + "DEPLOYMENT_PARAMETER_FOO": "test1", + "DEPLOYMENT_PARAMETER_BAR": "test2", + }, + }, + { + build: _deployTag, + want: map[string]string{ + "VELA_BUILD_APPROVED_AT": "1563474076", + "VELA_BUILD_APPROVED_BY": "OctoCat", + "VELA_BUILD_AUTHOR": "OctoKitty", + "VELA_BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "VELA_BUILD_BASE_REF": "", + "VELA_BUILD_BRANCH": "main", + "VELA_BUILD_CHANNEL": "TODO", + "VELA_BUILD_CLONE": "https://github.com/github/octocat.git", + "VELA_BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_CREATED": "1563474076", + "VELA_BUILD_DISTRIBUTION": "linux", + "VELA_BUILD_ENQUEUED": "1563474077", + "VELA_BUILD_EVENT": "deployment", + "VELA_BUILD_EVENT_ACTION": "", + "VELA_BUILD_HOST": "example.company.com", + "VELA_BUILD_LINK": "https://example.company.com/github/octocat/1", + "VELA_BUILD_MESSAGE": "First commit...", + "VELA_BUILD_NUMBER": "1", + "VELA_BUILD_PARENT": "1", + "VELA_BUILD_REF": "refs/tags/v0.1.0", + "VELA_BUILD_RUNTIME": "docker", + "VELA_BUILD_SENDER": "OctoKitty", + "VELA_BUILD_STARTED": "1563474078", + "VELA_BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_STATUS": "running", + "VELA_BUILD_TAG": "v0.1.0", + "VELA_BUILD_TARGET": "production", + "VELA_BUILD_TITLE": "push received from https://github.com/github/octocat", + "VELA_BUILD_WORKSPACE": "TODO", + "VELA_DEPLOYMENT": "production", + "VELA_DEPLOYMENT_NUMBER": "0", + "BUILD_AUTHOR": "OctoKitty", + "BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "BUILD_BASE_REF": "", + "BUILD_BRANCH": "main", + "BUILD_CHANNEL": "TODO", + "BUILD_CLONE": "https://github.com/github/octocat.git", + "BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_CREATED": "1563474076", + "BUILD_ENQUEUED": "1563474077", + "BUILD_EVENT": "deployment", + "BUILD_HOST": "example.company.com", + "BUILD_LINK": "https://example.company.com/github/octocat/1", + "BUILD_MESSAGE": "First commit...", + "BUILD_NUMBER": "1", + "BUILD_PARENT": "1", + "BUILD_REF": "refs/tags/v0.1.0", + "BUILD_SENDER": "OctoKitty", + "BUILD_STARTED": "1563474078", + "BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_STATUS": "running", + "BUILD_TAG": "v0.1.0", + "BUILD_TARGET": "production", + "BUILD_TITLE": "push received from https://github.com/github/octocat", + "BUILD_WORKSPACE": "TODO", + "DEPLOYMENT_PARAMETER_FOO": "test1", + "DEPLOYMENT_PARAMETER_BAR": "test2", + }, + }, + { + build: _pull, + want: map[string]string{ + "VELA_BUILD_APPROVED_AT": "1563474076", + "VELA_BUILD_APPROVED_BY": "OctoCat", + "VELA_BUILD_AUTHOR": "OctoKitty", + "VELA_BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "VELA_BUILD_BASE_REF": "", + "VELA_BUILD_BRANCH": "main", + "VELA_BUILD_CHANNEL": "TODO", + "VELA_BUILD_CLONE": "https://github.com/github/octocat.git", + "VELA_BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_CREATED": "1563474076", + "VELA_BUILD_DISTRIBUTION": "linux", + "VELA_BUILD_ENQUEUED": "1563474077", + "VELA_BUILD_EVENT": "pull_request", + "VELA_BUILD_EVENT_ACTION": "opened", + "VELA_BUILD_HOST": "example.company.com", + "VELA_BUILD_LINK": "https://example.company.com/github/octocat/1", + "VELA_BUILD_MESSAGE": "First commit...", + "VELA_BUILD_NUMBER": "1", + "VELA_BUILD_PARENT": "1", + "VELA_BUILD_PULL_REQUEST": "1", + "VELA_BUILD_REF": "refs/pulls/1/head", + "VELA_BUILD_RUNTIME": "docker", + "VELA_BUILD_SENDER": "OctoKitty", + "VELA_BUILD_STARTED": "1563474078", + "VELA_BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_STATUS": "running", + "VELA_BUILD_TITLE": "push received from https://github.com/github/octocat", + "VELA_BUILD_WORKSPACE": "TODO", + "VELA_PULL_REQUEST": "1", + "VELA_PULL_REQUEST_SOURCE": "changes", + "VELA_PULL_REQUEST_TARGET": "", + "BUILD_AUTHOR": "OctoKitty", + "BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "BUILD_BASE_REF": "", + "BUILD_BRANCH": "main", + "BUILD_CHANNEL": "TODO", + "BUILD_CLONE": "https://github.com/github/octocat.git", + "BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_CREATED": "1563474076", + "BUILD_ENQUEUED": "1563474077", + "BUILD_EVENT": "pull_request", + "BUILD_HOST": "example.company.com", + "BUILD_LINK": "https://example.company.com/github/octocat/1", + "BUILD_MESSAGE": "First commit...", + "BUILD_NUMBER": "1", + "BUILD_PARENT": "1", + "BUILD_PULL_REQUEST_NUMBER": "1", + "BUILD_REF": "refs/pulls/1/head", + "BUILD_SENDER": "OctoKitty", + "BUILD_STARTED": "1563474078", + "BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_STATUS": "running", + "BUILD_TITLE": "push received from https://github.com/github/octocat", + "BUILD_WORKSPACE": "TODO", + }, + }, + { + build: _tag, + want: map[string]string{ + "VELA_BUILD_APPROVED_AT": "1563474076", + "VELA_BUILD_APPROVED_BY": "OctoCat", + "VELA_BUILD_AUTHOR": "OctoKitty", + "VELA_BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "VELA_BUILD_BASE_REF": "", + "VELA_BUILD_BRANCH": "main", + "VELA_BUILD_CHANNEL": "TODO", + "VELA_BUILD_CLONE": "https://github.com/github/octocat.git", + "VELA_BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_CREATED": "1563474076", + "VELA_BUILD_DISTRIBUTION": "linux", + "VELA_BUILD_ENQUEUED": "1563474077", + "VELA_BUILD_EVENT": "tag", + "VELA_BUILD_EVENT_ACTION": "", + "VELA_BUILD_HOST": "example.company.com", + "VELA_BUILD_LINK": "https://example.company.com/github/octocat/1", + "VELA_BUILD_MESSAGE": "First commit...", + "VELA_BUILD_NUMBER": "1", + "VELA_BUILD_PARENT": "1", + "VELA_BUILD_REF": "refs/tags/v0.1.0", + "VELA_BUILD_RUNTIME": "docker", + "VELA_BUILD_SENDER": "OctoKitty", + "VELA_BUILD_STARTED": "1563474078", + "VELA_BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "VELA_BUILD_STATUS": "running", + "VELA_BUILD_TAG": "v0.1.0", + "VELA_BUILD_TITLE": "push received from https://github.com/github/octocat", + "VELA_BUILD_WORKSPACE": "TODO", + "BUILD_AUTHOR": "OctoKitty", + "BUILD_AUTHOR_EMAIL": "OctoKitty@github.com", + "BUILD_BASE_REF": "", + "BUILD_BRANCH": "main", + "BUILD_CHANNEL": "TODO", + "BUILD_CLONE": "https://github.com/github/octocat.git", + "BUILD_COMMIT": "48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_CREATED": "1563474076", + "BUILD_ENQUEUED": "1563474077", + "BUILD_EVENT": "tag", + "BUILD_HOST": "example.company.com", + "BUILD_LINK": "https://example.company.com/github/octocat/1", + "BUILD_MESSAGE": "First commit...", + "BUILD_NUMBER": "1", + "BUILD_PARENT": "1", + "BUILD_REF": "refs/tags/v0.1.0", + "BUILD_SENDER": "OctoKitty", + "BUILD_STARTED": "1563474078", + "BUILD_SOURCE": "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", + "BUILD_STATUS": "running", + "BUILD_TAG": "v0.1.0", + "BUILD_TITLE": "push received from https://github.com/github/octocat", + "BUILD_WORKSPACE": "TODO", + }, + }, + } + + // run test + for _, test := range tests { + got := test.build.Environment("TODO", "TODO") + + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("(Environment: -want +got):\n%s", diff) + } + } +} + +func TestTypes_Build_Getters(t *testing.T) { + // setup tests + tests := []struct { + build *Build + want *Build + }{ + { + build: testBuild(), + want: testBuild(), + }, + { + build: new(Build), + want: new(Build), + }, + } + + // run tests + for _, test := range tests { + if test.build.GetID() != test.want.GetID() { + t.Errorf("GetID is %v, want %v", test.build.GetID(), test.want.GetID()) + } + + if !reflect.DeepEqual(test.build.GetRepo(), test.want.GetRepo()) { + t.Errorf("GetRepo is %v, want %v", test.build.GetRepo(), test.want.GetRepo()) + } + + if test.build.GetPipelineID() != test.want.GetPipelineID() { + t.Errorf("GetPipelineID is %v, want %v", test.build.GetPipelineID(), test.want.GetPipelineID()) + } + + if test.build.GetNumber() != test.want.GetNumber() { + t.Errorf("GetNumber is %v, want %v", test.build.GetNumber(), test.want.GetNumber()) + } + + if test.build.GetParent() != test.want.GetParent() { + t.Errorf("GetParent is %v, want %v", test.build.GetParent(), test.want.GetParent()) + } + + if test.build.GetEvent() != test.want.GetEvent() { + t.Errorf("GetEvent is %v, want %v", test.build.GetEvent(), test.want.GetEvent()) + } + + if test.build.GetEventAction() != test.want.GetEventAction() { + t.Errorf("GetEventAction is %v, want %v", test.build.GetEventAction(), test.want.GetEventAction()) + } + + if test.build.GetStatus() != test.want.GetStatus() { + t.Errorf("GetStatus is %v, want %v", test.build.GetStatus(), test.want.GetStatus()) + } + + if test.build.GetError() != test.want.GetError() { + t.Errorf("GetError is %v, want %v", test.build.GetError(), test.want.GetError()) + } + + if test.build.GetEnqueued() != test.want.GetEnqueued() { + t.Errorf("GetEnqueued is %v, want %v", test.build.GetEnqueued(), test.want.GetEnqueued()) + } + + if test.build.GetCreated() != test.want.GetCreated() { + t.Errorf("GetCreated is %v, want %v", test.build.GetCreated(), test.want.GetCreated()) + } + + if test.build.GetStarted() != test.want.GetStarted() { + t.Errorf("GetStarted is %v, want %v", test.build.GetStarted(), test.want.GetStarted()) + } + + if test.build.GetFinished() != test.want.GetFinished() { + t.Errorf("GetFinished is %v, want %v", test.build.GetFinished(), test.want.GetFinished()) + } + + if test.build.GetDeploy() != test.want.GetDeploy() { + t.Errorf("GetDeploy is %v, want %v", test.build.GetDeploy(), test.want.GetDeploy()) + } + + if test.build.GetDeployNumber() != test.want.GetDeployNumber() { + t.Errorf("GetDeployNumber is %v, want %v", test.build.GetDeployNumber(), test.want.GetDeployNumber()) + } + + if !reflect.DeepEqual(test.build.GetDeployPayload(), test.want.GetDeployPayload()) { + t.Errorf("GetDeployPayload is %v, want %v", test.build.GetDeployPayload(), test.want.GetDeployPayload()) + } + + if test.build.GetClone() != test.want.GetClone() { + t.Errorf("GetClone is %v, want %v", test.build.GetClone(), test.want.GetClone()) + } + + if test.build.GetSource() != test.want.GetSource() { + t.Errorf("GetSource is %v, want %v", test.build.GetSource(), test.want.GetSource()) + } + + if test.build.GetTitle() != test.want.GetTitle() { + t.Errorf("GetTitle is %v, want %v", test.build.GetTitle(), test.want.GetTitle()) + } + + if test.build.GetMessage() != test.want.GetMessage() { + t.Errorf("GetMessage is %v, want %v", test.build.GetMessage(), test.want.GetMessage()) + } + + if test.build.GetCommit() != test.want.GetCommit() { + t.Errorf("GetCommit is %v, want %v", test.build.GetCommit(), test.want.GetCommit()) + } + + if test.build.GetSender() != test.want.GetSender() { + t.Errorf("GetSender is %v, want %v", test.build.GetSender(), test.want.GetSender()) + } + + if test.build.GetAuthor() != test.want.GetAuthor() { + t.Errorf("GetAuthor is %v, want %v", test.build.GetAuthor(), test.want.GetAuthor()) + } + + if test.build.GetEmail() != test.want.GetEmail() { + t.Errorf("GetEmail is %v, want %v", test.build.GetEmail(), test.want.GetEmail()) + } + + if test.build.GetLink() != test.want.GetLink() { + t.Errorf("GetLink is %v, want %v", test.build.GetLink(), test.want.GetLink()) + } + + if test.build.GetBranch() != test.want.GetBranch() { + t.Errorf("GetBranch is %v, want %v", test.build.GetBranch(), test.want.GetBranch()) + } + + if test.build.GetRef() != test.want.GetRef() { + t.Errorf("GetRef is %v, want %v", test.build.GetRef(), test.want.GetRef()) + } + + if test.build.GetBaseRef() != test.want.GetBaseRef() { + t.Errorf("GetBaseRef is %v, want %v", test.build.GetBaseRef(), test.want.GetBaseRef()) + } + + if test.build.GetHeadRef() != test.want.GetHeadRef() { + t.Errorf("GetHeadRef is %v, want %v", test.build.GetHeadRef(), test.want.GetHeadRef()) + } + + if test.build.GetHost() != test.want.GetHost() { + t.Errorf("GetHost is %v, want %v", test.build.GetHost(), test.want.GetHost()) + } + + if test.build.GetRuntime() != test.want.GetRuntime() { + t.Errorf("GetRuntime is %v, want %v", test.build.GetRuntime(), test.want.GetRuntime()) + } + + if test.build.GetDistribution() != test.want.GetDistribution() { + t.Errorf("GetDistribution is %v, want %v", test.build.GetDistribution(), test.want.GetDistribution()) + } + + if test.build.GetApprovedAt() != test.want.GetApprovedAt() { + t.Errorf("GetApprovedAt is %v, want %v", test.build.GetApprovedAt(), test.want.GetApprovedAt()) + } + + if test.build.GetApprovedBy() != test.want.GetApprovedBy() { + t.Errorf("GetApprovedBy is %v, want %v", test.build.GetApprovedBy(), test.want.GetApprovedBy()) + } + } +} + +func TestTypes_Build_Setters(t *testing.T) { + // setup types + var b *Build + + // setup tests + tests := []struct { + build *Build + want *Build + }{ + { + build: testBuild(), + want: testBuild(), + }, + { + build: b, + want: new(Build), + }, + } + + // run tests + for _, test := range tests { + test.build.SetID(test.want.GetID()) + test.build.SetRepo(test.want.GetRepo()) + test.build.SetPipelineID(test.want.GetPipelineID()) + test.build.SetNumber(test.want.GetNumber()) + test.build.SetParent(test.want.GetParent()) + test.build.SetEvent(test.want.GetEvent()) + test.build.SetEventAction(test.want.GetEventAction()) + test.build.SetStatus(test.want.GetStatus()) + test.build.SetError(test.want.GetError()) + test.build.SetEnqueued(test.want.GetEnqueued()) + test.build.SetCreated(test.want.GetCreated()) + test.build.SetStarted(test.want.GetStarted()) + test.build.SetFinished(test.want.GetFinished()) + test.build.SetDeploy(test.want.GetDeploy()) + test.build.SetDeployNumber(test.want.GetDeployNumber()) + test.build.SetDeployPayload(test.want.GetDeployPayload()) + test.build.SetClone(test.want.GetClone()) + test.build.SetSource(test.want.GetSource()) + test.build.SetTitle(test.want.GetTitle()) + test.build.SetMessage(test.want.GetMessage()) + test.build.SetCommit(test.want.GetCommit()) + test.build.SetSender(test.want.GetSender()) + test.build.SetAuthor(test.want.GetAuthor()) + test.build.SetEmail(test.want.GetEmail()) + test.build.SetLink(test.want.GetLink()) + test.build.SetBranch(test.want.GetBranch()) + test.build.SetRef(test.want.GetRef()) + test.build.SetBaseRef(test.want.GetBaseRef()) + test.build.SetHeadRef(test.want.GetHeadRef()) + test.build.SetHost(test.want.GetHost()) + test.build.SetRuntime(test.want.GetRuntime()) + test.build.SetDistribution(test.want.GetDistribution()) + test.build.SetApprovedAt(test.want.GetApprovedAt()) + test.build.SetApprovedBy(test.want.GetApprovedBy()) + + if test.build.GetID() != test.want.GetID() { + t.Errorf("SetID is %v, want %v", test.build.GetID(), test.want.GetID()) + } + + if !reflect.DeepEqual(test.build.GetRepo(), test.want.GetRepo()) { + t.Errorf("SetRepo is %v, want %v", test.build.GetRepo(), test.want.GetRepo()) + } + + if test.build.GetPipelineID() != test.want.GetPipelineID() { + t.Errorf("SetPipelineID is %v, want %v", test.build.GetPipelineID(), test.want.GetPipelineID()) + } + + if test.build.GetNumber() != test.want.GetNumber() { + t.Errorf("SetNumber is %v, want %v", test.build.GetNumber(), test.want.GetNumber()) + } + + if test.build.GetParent() != test.want.GetParent() { + t.Errorf("SetParent is %v, want %v", test.build.GetParent(), test.want.GetParent()) + } + + if test.build.GetEvent() != test.want.GetEvent() { + t.Errorf("SetEvent is %v, want %v", test.build.GetEvent(), test.want.GetEvent()) + } + + if test.build.GetEventAction() != test.want.GetEventAction() { + t.Errorf("SetEventAction is %v, want %v", test.build.GetEventAction(), test.want.GetEventAction()) + } + + if test.build.GetStatus() != test.want.GetStatus() { + t.Errorf("SetStatus is %v, want %v", test.build.GetStatus(), test.want.GetStatus()) + } + + if test.build.GetError() != test.want.GetError() { + t.Errorf("SetError is %v, want %v", test.build.GetError(), test.want.GetError()) + } + + if test.build.GetEnqueued() != test.want.GetEnqueued() { + t.Errorf("SetEnqueued is %v, want %v", test.build.GetEnqueued(), test.want.GetEnqueued()) + } + + if test.build.GetCreated() != test.want.GetCreated() { + t.Errorf("SetCreated is %v, want %v", test.build.GetCreated(), test.want.GetCreated()) + } + + if test.build.GetStarted() != test.want.GetStarted() { + t.Errorf("SetStarted is %v, want %v", test.build.GetStarted(), test.want.GetStarted()) + } + + if test.build.GetFinished() != test.want.GetFinished() { + t.Errorf("SetFinished is %v, want %v", test.build.GetFinished(), test.want.GetFinished()) + } + + if test.build.GetDeploy() != test.want.GetDeploy() { + t.Errorf("SetDeploy is %v, want %v", test.build.GetDeploy(), test.want.GetDeploy()) + } + + if test.build.GetDeployNumber() != test.want.GetDeployNumber() { + t.Errorf("SetDeployNumber is %v, want %v", test.build.GetDeployNumber(), test.want.GetDeployNumber()) + } + + if !reflect.DeepEqual(test.build.GetDeployPayload(), test.want.GetDeployPayload()) { + t.Errorf("GetDeployPayload is %v, want %v", test.build.GetDeployPayload(), test.want.GetDeployPayload()) + } + + if test.build.GetClone() != test.want.GetClone() { + t.Errorf("SetClone is %v, want %v", test.build.GetClone(), test.want.GetClone()) + } + + if test.build.GetSource() != test.want.GetSource() { + t.Errorf("SetSource is %v, want %v", test.build.GetSource(), test.want.GetSource()) + } + + if test.build.GetTitle() != test.want.GetTitle() { + t.Errorf("SetTitle is %v, want %v", test.build.GetTitle(), test.want.GetTitle()) + } + + if test.build.GetMessage() != test.want.GetMessage() { + t.Errorf("SetMessage is %v, want %v", test.build.GetMessage(), test.want.GetMessage()) + } + + if test.build.GetCommit() != test.want.GetCommit() { + t.Errorf("SetCommit is %v, want %v", test.build.GetCommit(), test.want.GetCommit()) + } + + if test.build.GetSender() != test.want.GetSender() { + t.Errorf("SetSender is %v, want %v", test.build.GetSender(), test.want.GetSender()) + } + + if test.build.GetAuthor() != test.want.GetAuthor() { + t.Errorf("SetAuthor is %v, want %v", test.build.GetAuthor(), test.want.GetAuthor()) + } + + if test.build.GetEmail() != test.want.GetEmail() { + t.Errorf("SetEmail is %v, want %v", test.build.GetEmail(), test.want.GetEmail()) + } + + if test.build.GetLink() != test.want.GetLink() { + t.Errorf("SetLink is %v, want %v", test.build.GetLink(), test.want.GetLink()) + } + + if test.build.GetBranch() != test.want.GetBranch() { + t.Errorf("SetBranch is %v, want %v", test.build.GetBranch(), test.want.GetBranch()) + } + + if test.build.GetRef() != test.want.GetRef() { + t.Errorf("SetRef is %v, want %v", test.build.GetRef(), test.want.GetRef()) + } + + if test.build.GetBaseRef() != test.want.GetBaseRef() { + t.Errorf("SetBaseRef is %v, want %v", test.build.GetBaseRef(), test.want.GetBaseRef()) + } + + if test.build.GetHeadRef() != test.want.GetHeadRef() { + t.Errorf("SetHeadRef is %v, want %v", test.build.GetHeadRef(), test.want.GetHeadRef()) + } + + if test.build.GetHost() != test.want.GetHost() { + t.Errorf("SetHost is %v, want %v", test.build.GetHost(), test.want.GetHost()) + } + + if test.build.GetRuntime() != test.want.GetRuntime() { + t.Errorf("SetRuntime is %v, want %v", test.build.GetRuntime(), test.want.GetRuntime()) + } + + if test.build.GetDistribution() != test.want.GetDistribution() { + t.Errorf("SetDistribution is %v, want %v", test.build.GetDistribution(), test.want.GetDistribution()) + } + + if test.build.GetApprovedAt() != test.want.GetApprovedAt() { + t.Errorf("SetApprovedAt is %v, want %v", test.build.GetApprovedAt(), test.want.GetApprovedAt()) + } + + if test.build.GetApprovedBy() != test.want.GetApprovedBy() { + t.Errorf("SetApprovedBy is %v, want %v", test.build.GetApprovedBy(), test.want.GetApprovedBy()) + } + } +} + +func TestTypes_Build_String(t *testing.T) { + // setup types + b := testBuild() + + want := fmt.Sprintf(`{ + ApprovedAt: %d, + ApprovedBy: %s, + Author: %s, + BaseRef: %s, + Branch: %s, + Clone: %s, + Commit: %s, + Created: %d, + Deploy: %s, + DeployNumber: %d, + DeployPayload: %s, + Distribution: %s, + Email: %s, + Enqueued: %d, + Error: %s, + Event: %s, + EventAction: %s, + Finished: %d, + HeadRef: %s, + Host: %s, + ID: %d, + Link: %s, + Message: %s, + Number: %d, + Parent: %d, + PipelineID: %d, + Ref: %s, + Repo: %s, + Runtime: %s, + Sender: %s, + Source: %s, + Started: %d, + Status: %s, + Title: %s, +}`, + b.GetApprovedAt(), + b.GetApprovedBy(), + b.GetAuthor(), + b.GetBaseRef(), + b.GetBranch(), + b.GetClone(), + b.GetCommit(), + b.GetCreated(), + b.GetDeploy(), + b.GetDeployNumber(), + b.GetDeployPayload(), + b.GetDistribution(), + b.GetEmail(), + b.GetEnqueued(), + b.GetError(), + b.GetEvent(), + b.GetEventAction(), + b.GetFinished(), + b.GetHeadRef(), + b.GetHost(), + b.GetID(), + b.GetLink(), + b.GetMessage(), + b.GetNumber(), + b.GetParent(), + b.GetPipelineID(), + b.GetRef(), + b.GetRepo().GetFullName(), + b.GetRuntime(), + b.GetSender(), + b.GetSource(), + b.GetStarted(), + b.GetStatus(), + b.GetTitle(), + ) + + // run test + got := b.String() + + if !reflect.DeepEqual(got, want) { + t.Errorf("String is %v, want %v", got, want) + } +} + +// testBuild is a test helper function to create a Build +// type with all fields set to a fake value. +func testBuild() *Build { + b := new(Build) + + b.SetID(1) + b.SetRepo(testRepo()) + b.SetPipelineID(1) + b.SetNumber(1) + b.SetParent(1) + b.SetEvent("push") + b.SetStatus("running") + b.SetError("") + b.SetEnqueued(1563474077) + b.SetCreated(1563474076) + b.SetStarted(1563474078) + b.SetFinished(1563474079) + b.SetDeploy("") + b.SetDeployNumber(0) + b.SetDeployPayload(raw.StringSliceMap{"foo": "test1"}) + b.SetClone("https://github.com/github/octocat.git") + b.SetSource("https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163") + b.SetTitle("push received from https://github.com/github/octocat") + b.SetMessage("First commit...") + b.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") + b.SetSender("OctoKitty") + b.SetAuthor("OctoKitty") + b.SetEmail("OctoKitty@github.com") + b.SetLink("https://example.company.com/github/octocat/1") + b.SetBranch("main") + b.SetRef("refs/heads/main") + b.SetBaseRef("") + b.SetHeadRef("changes") + b.SetHost("example.company.com") + b.SetRuntime("docker") + b.SetDistribution("linux") + b.SetApprovedAt(1563474076) + b.SetApprovedBy("OctoCat") + + return b +} diff --git a/api/types/executor.go b/api/types/executor.go index 706862f24..45bbfce2e 100644 --- a/api/types/executor.go +++ b/api/types/executor.go @@ -6,7 +6,6 @@ import ( "fmt" "strings" - "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" ) @@ -18,8 +17,7 @@ type Executor struct { Host *string `json:"host,omitempty"` Runtime *string `json:"runtime,omitempty"` Distribution *string `json:"distribution,omitempty"` - Build *library.Build `json:"build,omitempty"` - Repo *Repo `json:"repo,omitempty"` + Build *Build `json:"build,omitempty"` Pipeline *pipeline.Build `json:"pipeline,omitempty"` } @@ -79,28 +77,15 @@ func (e *Executor) GetDistribution() string { // // When the provided Executor type is nil, or the field within // the type is nil, it returns the zero value for the field. -func (e *Executor) GetBuild() library.Build { +func (e *Executor) GetBuild() Build { // return zero value if Executor type or Build field is nil if e == nil || e.Build == nil { - return library.Build{} + return Build{} } return *e.Build } -// GetRepo returns the Repo field. -// -// When the provided Executor type is nil, or the field within -// the type is nil, it returns the zero value for the field. -func (e *Executor) GetRepo() Repo { - // return zero value if Executor type or Repo field is nil - if e == nil || e.Repo == nil { - return Repo{} - } - - return *e.Repo -} - // GetPipeline returns the Pipeline field. // // When the provided Executor type is nil, or the field within @@ -170,7 +155,7 @@ func (e *Executor) SetDistribution(v string) { // // When the provided Executor type is nil, it // will set nothing and immediately return. -func (e *Executor) SetBuild(v library.Build) { +func (e *Executor) SetBuild(v Build) { // return if Executor type is nil if e == nil { return @@ -179,19 +164,6 @@ func (e *Executor) SetBuild(v library.Build) { e.Build = &v } -// SetRepo sets the Repo field. -// -// When the provided Executor type is nil, it -// will set nothing and immediately return. -func (e *Executor) SetRepo(v Repo) { - // return if Executor type is nil - if e == nil { - return - } - - e.Repo = &v -} - // SetPipeline sets the pipeline Build field. // // When the provided Executor type is nil, it @@ -212,7 +184,6 @@ func (e *Executor) String() string { Distribution: %s, Host: %s, ID: %d, - Repo: %v, Runtime: %s, Pipeline: %v, }`, @@ -220,7 +191,6 @@ func (e *Executor) String() string { e.GetDistribution(), e.GetHost(), e.GetID(), - strings.ReplaceAll(e.Repo.String(), " ", " "), e.GetRuntime(), e.GetPipeline(), ) diff --git a/api/types/executor_test.go b/api/types/executor_test.go index 72dbac4e4..e47472b8a 100644 --- a/api/types/executor_test.go +++ b/api/types/executor_test.go @@ -8,9 +8,7 @@ import ( "strings" "testing" - "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" - "github.com/go-vela/types/raw" ) func TestTypes_Executor_Getters(t *testing.T) { @@ -51,10 +49,6 @@ func TestTypes_Executor_Getters(t *testing.T) { t.Errorf("GetBuild is %v, want %v", test.executor.GetBuild(), test.want.GetBuild()) } - if !reflect.DeepEqual(test.executor.GetRepo(), test.want.GetRepo()) { - t.Errorf("GetRepo is %v, want %v", test.executor.GetRepo(), test.want.GetRepo()) - } - if !reflect.DeepEqual(test.executor.GetPipeline(), test.want.GetPipeline()) { t.Errorf("GetPipeline is %v, want %v", test.executor.GetPipeline(), test.want.GetPipeline()) } @@ -87,7 +81,6 @@ func TestTypes_Executor_Setters(t *testing.T) { test.executor.SetRuntime(test.want.GetRuntime()) test.executor.SetDistribution(test.want.GetDistribution()) test.executor.SetBuild(test.want.GetBuild()) - test.executor.SetRepo(test.want.GetRepo()) test.executor.SetPipeline(test.want.GetPipeline()) if test.executor.GetID() != test.want.GetID() { @@ -110,10 +103,6 @@ func TestTypes_Executor_Setters(t *testing.T) { t.Errorf("SetBuild is %v, want %v", test.executor.GetBuild(), test.want.GetBuild()) } - if !reflect.DeepEqual(test.executor.GetRepo(), test.want.GetRepo()) { - t.Errorf("SetRepo is %v, want %v", test.executor.GetRepo(), test.want.GetRepo()) - } - if !reflect.DeepEqual(test.executor.GetPipeline(), test.want.GetPipeline()) { t.Errorf("SetPipeline is %v, want %v", test.executor.GetPipeline(), test.want.GetPipeline()) } @@ -129,7 +118,6 @@ func TestTypes_Executor_String(t *testing.T) { Distribution: %s, Host: %s, ID: %d, - Repo: %v, Runtime: %s, Pipeline: %v, }`, @@ -137,7 +125,6 @@ func TestTypes_Executor_String(t *testing.T) { e.GetDistribution(), e.GetHost(), e.GetID(), - strings.ReplaceAll(e.Repo.String(), " ", " "), e.GetRuntime(), e.GetPipeline(), ) @@ -160,7 +147,6 @@ func testExecutor() *Executor { e.SetRuntime("docker") e.SetDistribution("linux") e.SetBuild(*testBuild()) - e.SetRepo(*testRepo()) e.SetPipeline(pipeline.Build{ Version: "1", ID: "github_octocat_1", @@ -195,47 +181,3 @@ func testExecutor() *Executor { return e } - -// testBuild is a test helper function to create a Build -// type with all fields set to a fake value. -// -// TODO: remove this function once the Build type is moved to server. -func testBuild() *library.Build { - b := new(library.Build) - - b.SetID(1) - b.SetRepoID(1) - b.SetPipelineID(1) - b.SetNumber(1) - b.SetParent(1) - b.SetEvent("push") - b.SetStatus("running") - b.SetError("") - b.SetEnqueued(1563474077) - b.SetCreated(1563474076) - b.SetStarted(1563474078) - b.SetFinished(1563474079) - b.SetDeploy("") - b.SetDeployNumber(0) - b.SetDeployPayload(raw.StringSliceMap{"foo": "test1"}) - b.SetClone("https://github.com/github/octocat.git") - b.SetSource("https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163") - b.SetTitle("push received from https://github.com/github/octocat") - b.SetMessage("First commit...") - b.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") - b.SetSender("OctoKitty") - b.SetAuthor("OctoKitty") - b.SetEmail("OctoKitty@github.com") - b.SetLink("https://example.company.com/github/octocat/1") - b.SetBranch("main") - b.SetRef("refs/heads/main") - b.SetBaseRef("") - b.SetHeadRef("changes") - b.SetHost("example.company.com") - b.SetRuntime("docker") - b.SetDistribution("linux") - b.SetApprovedAt(1563474076) - b.SetApprovedBy("OctoCat") - - return b -} diff --git a/api/types/queue_build.go b/api/types/queue_build.go new file mode 100644 index 000000000..8b39c3bc7 --- /dev/null +++ b/api/types/queue_build.go @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import "fmt" + +// QueueBuild is the API representation of the builds in the queue. +// +// swagger:model QueueBuild +type QueueBuild struct { + Status *string `json:"status,omitempty"` + Number *int32 `json:"number,omitempty"` + Created *int64 `json:"created,omitempty"` + FullName *string `json:"full_name,omitempty"` +} + +// GetStatus returns the Status field. +// +// When the provided QueueBuild type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *QueueBuild) GetStatus() string { + // return zero value if QueueBuild type or Status field is nil + if b == nil || b.Status == nil { + return "" + } + + return *b.Status +} + +// GetNumber returns the Number field. +// +// When the provided QueueBuild type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *QueueBuild) GetNumber() int32 { + // return zero value if QueueBuild type or Number field is nil + if b == nil || b.Number == nil { + return 0 + } + + return *b.Number +} + +// GetCreated returns the Created field. +// +// When the provided QueueBuild type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *QueueBuild) GetCreated() int64 { + // return zero value if QueueBuild type or Created field is nil + if b == nil || b.Created == nil { + return 0 + } + + return *b.Created +} + +// GetFullName returns the FullName field. +// +// When the provided QueueBuild type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (b *QueueBuild) GetFullName() string { + // return zero value if QueueBuild type or FullName field is nil + if b == nil || b.FullName == nil { + return "" + } + + return *b.FullName +} + +// SetStatus sets the Status field. +// +// When the provided QueueBuild type is nil, it +// will set nothing and immediately return. +func (b *QueueBuild) SetStatus(v string) { + // return if QueueBuild type is nil + if b == nil { + return + } + + b.Status = &v +} + +// SetNumber sets the Number field. +// +// When the provided QueueBuild type is nil, it +// will set nothing and immediately return. +func (b *QueueBuild) SetNumber(v int32) { + // return if QueueBuild type is nil + if b == nil { + return + } + + b.Number = &v +} + +// SetCreated sets the Created field. +// +// When the provided QueueBuild type is nil, it +// will set nothing and immediately return. +func (b *QueueBuild) SetCreated(v int64) { + // return if QueueBuild type is nil + if b == nil { + return + } + + b.Created = &v +} + +// SetFullName sets the FullName field. +// +// When the provided QueueBuild type is nil, it +// will set nothing and immediately return. +func (b *QueueBuild) SetFullName(v string) { + // return if QueueBuild type is nil + if b == nil { + return + } + + b.FullName = &v +} + +// String implements the Stringer interface for the QueueBuild type. +func (b *QueueBuild) String() string { + return fmt.Sprintf(`{ + Created: %d, + FullName: %s, + Number: %d, + Status: %s, +}`, + b.GetCreated(), + b.GetFullName(), + b.GetNumber(), + b.GetStatus(), + ) +} diff --git a/api/types/queue_build_test.go b/api/types/queue_build_test.go new file mode 100644 index 000000000..6351b8624 --- /dev/null +++ b/api/types/queue_build_test.go @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "fmt" + "reflect" + "testing" +) + +func TestTypes_QueueBuild_Getters(t *testing.T) { + // setup tests + tests := []struct { + buildQueue *QueueBuild + want *QueueBuild + }{ + { + buildQueue: testQueueBuild(), + want: testQueueBuild(), + }, + { + buildQueue: new(QueueBuild), + want: new(QueueBuild), + }, + } + + // run tests + for _, test := range tests { + if test.buildQueue.GetNumber() != test.want.GetNumber() { + t.Errorf("GetNumber is %v, want %v", test.buildQueue.GetNumber(), test.want.GetNumber()) + } + + if test.buildQueue.GetStatus() != test.want.GetStatus() { + t.Errorf("GetStatus is %v, want %v", test.buildQueue.GetStatus(), test.want.GetStatus()) + } + + if test.buildQueue.GetCreated() != test.want.GetCreated() { + t.Errorf("GetCreated is %v, want %v", test.buildQueue.GetCreated(), test.want.GetCreated()) + } + + if test.buildQueue.GetFullName() != test.want.GetFullName() { + t.Errorf("GetFullName is %v, want %v", test.buildQueue.GetFullName(), test.want.GetFullName()) + } + } +} + +func TestTypes_QueueBuild_Setters(t *testing.T) { + // setup types + var b *QueueBuild + + // setup tests + tests := []struct { + buildQueue *QueueBuild + want *QueueBuild + }{ + { + buildQueue: testQueueBuild(), + want: testQueueBuild(), + }, + { + buildQueue: b, + want: new(QueueBuild), + }, + } + + // run tests + for _, test := range tests { + test.buildQueue.SetNumber(test.want.GetNumber()) + test.buildQueue.SetStatus(test.want.GetStatus()) + test.buildQueue.SetCreated(test.want.GetCreated()) + test.buildQueue.SetFullName(test.want.GetFullName()) + + if test.buildQueue.GetNumber() != test.want.GetNumber() { + t.Errorf("SetNumber is %v, want %v", test.buildQueue.GetNumber(), test.want.GetNumber()) + } + + if test.buildQueue.GetStatus() != test.want.GetStatus() { + t.Errorf("SetStatus is %v, want %v", test.buildQueue.GetStatus(), test.want.GetStatus()) + } + + if test.buildQueue.GetCreated() != test.want.GetCreated() { + t.Errorf("SetCreated is %v, want %v", test.buildQueue.GetCreated(), test.want.GetCreated()) + } + + if test.buildQueue.GetFullName() != test.want.GetFullName() { + t.Errorf("SetFullName is %v, want %v", test.buildQueue.GetFullName(), test.want.GetFullName()) + } + } +} + +func TestTypes_QueueBuild_String(t *testing.T) { + // setup types + b := testQueueBuild() + + want := fmt.Sprintf(`{ + Created: %d, + FullName: %s, + Number: %d, + Status: %s, +}`, + b.GetCreated(), + b.GetFullName(), + b.GetNumber(), + b.GetStatus(), + ) + + // run test + got := b.String() + + if !reflect.DeepEqual(got, want) { + t.Errorf("String is %v, want %v", got, want) + } +} + +// testQueueBuild is a test helper function to create a QueueBuild +// type with all fields set to a fake value. +func testQueueBuild() *QueueBuild { + b := new(QueueBuild) + + b.SetNumber(1) + b.SetStatus("running") + b.SetCreated(1563474076) + b.SetFullName("github/octocat") + + return b +} diff --git a/api/types/repo_test.go b/api/types/repo_test.go index c632b471d..2cbe84639 100644 --- a/api/types/repo_test.go +++ b/api/types/repo_test.go @@ -342,12 +342,8 @@ func testRepo() *Repo { e, _ := testEvents() - owner := new(User) - owner.SetID(1) - owner.SetName("octocat") - r.SetID(1) - r.SetOwner(owner) + r.SetOwner(testUser()) r.SetOrg("github") r.SetName("octocat") r.SetFullName("github/octocat") diff --git a/api/types/worker.go b/api/types/worker.go index 4c06a0e69..af001fa80 100644 --- a/api/types/worker.go +++ b/api/types/worker.go @@ -4,26 +4,24 @@ package types import ( "fmt" - - "github.com/go-vela/types/library" ) // Worker is the API representation of a worker. // // swagger:model Worker type Worker struct { - ID *int64 `json:"id,omitempty"` - Hostname *string `json:"hostname,omitempty"` - Address *string `json:"address,omitempty"` - Routes *[]string `json:"routes,omitempty"` - Active *bool `json:"active,omitempty"` - Status *string `json:"status,omitempty"` - LastStatusUpdateAt *int64 `json:"last_status_update_at,omitempty"` - RunningBuilds *[]*library.Build `json:"running_builds,omitempty"` - LastBuildStartedAt *int64 `json:"last_build_started_at,omitempty"` - LastBuildFinishedAt *int64 `json:"last_build_finished_at,omitempty"` - LastCheckedIn *int64 `json:"last_checked_in,omitempty"` - BuildLimit *int64 `json:"build_limit,omitempty"` + ID *int64 `json:"id,omitempty"` + Hostname *string `json:"hostname,omitempty"` + Address *string `json:"address,omitempty"` + Routes *[]string `json:"routes,omitempty"` + Active *bool `json:"active,omitempty"` + Status *string `json:"status,omitempty"` + LastStatusUpdateAt *int64 `json:"last_status_update_at,omitempty"` + RunningBuilds *[]*Build `json:"running_builds,omitempty"` + LastBuildStartedAt *int64 `json:"last_build_started_at,omitempty"` + LastBuildFinishedAt *int64 `json:"last_build_finished_at,omitempty"` + LastCheckedIn *int64 `json:"last_checked_in,omitempty"` + BuildLimit *int64 `json:"build_limit,omitempty"` } // GetID returns the ID field. @@ -121,10 +119,10 @@ func (w *Worker) GetLastStatusUpdateAt() int64 { // // When the provided Worker type is nil, or the field within // the type is nil, it returns the zero value for the field. -func (w *Worker) GetRunningBuilds() []*library.Build { +func (w *Worker) GetRunningBuilds() []*Build { // return zero value if Worker type or RunningBuilds field is nil if w == nil || w.RunningBuilds == nil { - return []*library.Build{} + return []*Build{} } return *w.RunningBuilds @@ -277,7 +275,7 @@ func (w *Worker) SetLastStatusUpdateAt(v int64) { // // When the provided Worker type is nil, it // will set nothing and immediately return. -func (w *Worker) SetRunningBuilds(builds []*library.Build) { +func (w *Worker) SetRunningBuilds(builds []*Build) { // return if Worker type is nil if w == nil { return diff --git a/api/types/worker_test.go b/api/types/worker_test.go index b1cc06fdb..633b7163d 100644 --- a/api/types/worker_test.go +++ b/api/types/worker_test.go @@ -7,8 +7,6 @@ import ( "reflect" "testing" "time" - - "github.com/go-vela/types/library" ) func TestTypes_Worker_Getters(t *testing.T) { @@ -202,7 +200,7 @@ func TestTypes_Worker_String(t *testing.T) { // testWorker is a test helper function to create a Worker // type with all fields set to a fake value. func testWorker() *Worker { - b := new(library.Build) + b := new(Build) b.SetID(1) w := new(Worker) @@ -214,7 +212,7 @@ func testWorker() *Worker { w.SetActive(true) w.SetStatus("available") w.SetLastStatusUpdateAt(time.Time{}.UTC().Unix()) - w.SetRunningBuilds([]*library.Build{b}) + w.SetRunningBuilds([]*Build{b}) w.SetLastBuildStartedAt(time.Time{}.UTC().Unix()) w.SetLastBuildFinishedAt(time.Time{}.UTC().Unix()) w.SetLastCheckedIn(time.Time{}.UTC().Unix()) diff --git a/api/webhook/post.go b/api/webhook/post.go index 8f6ef750e..20600d525 100644 --- a/api/webhook/post.go +++ b/api/webhook/post.go @@ -208,7 +208,7 @@ func PostWebhook(c *gin.Context) { } // set the RepoID fields - b.SetRepoID(repo.GetID()) + b.SetRepo(repo) h.SetRepoID(repo.GetID()) // send API call to capture the last hook for the repo @@ -299,7 +299,6 @@ func PostWebhook(c *gin.Context) { // construct CompileAndPublishConfig config := build.CompileAndPublishConfig{ Build: b, - Repo: repo, Metadata: m, BaseErr: baseErr, Source: "webhook", @@ -338,7 +337,7 @@ func PostWebhook(c *gin.Context) { } // capture the build and repo from the items - b, repo = item.Build, item.Repo + b = item.Build // set hook build_id to the generated build id h.SetBuildID(b.GetID()) @@ -351,7 +350,7 @@ func PostWebhook(c *gin.Context) { deployment := webhook.Deployment deployment.SetRepoID(repo.GetID()) - deployment.SetBuilds([]*library.Build{b}) + deployment.SetBuilds([]*library.Build{b.ToLibrary()}) _, err := database.FromContext(c).CreateDeployment(c, deployment) if err != nil { @@ -373,8 +372,10 @@ func PostWebhook(c *gin.Context) { return } } else { - build := append(d.GetBuilds(), b) + build := append(d.GetBuilds(), b.ToLibrary()) + d.SetBuilds(build) + _, err := database.FromContext(c).UpdateDeployment(ctx, d) if err != nil { retErr := fmt.Errorf("%s: failed to update deployment %s/%d: %w", baseErr, repo.GetFullName(), d.GetNumber(), err) @@ -401,7 +402,7 @@ func PostWebhook(c *gin.Context) { for _, rB := range rBs { // call auto cancel routine - canceled, err := build.AutoCancel(c, b, rB, repo, p.Metadata.AutoCancel) + canceled, err := build.AutoCancel(c, b, rB, p.Metadata.AutoCancel) if err != nil { // continue cancel loop if error, but log based on type of error if canceled { @@ -650,7 +651,7 @@ func RenameRepository(ctx context.Context, h *library.Hook, r *types.Repo, c *gi return nil, fmt.Errorf("unable to get build count for repo %s: %w", dbR.GetFullName(), err) } - builds := []*library.Build{} + builds := []*types.Build{} page = 1 // capture all builds belonging to repo in database for build := int64(0); build < t; build += 100 { @@ -701,7 +702,7 @@ func RenameRepository(ctx context.Context, h *library.Hook, r *types.Repo, c *gi // gatekeepBuild is a helper function that will set the status of a build to 'pending approval' and // send a status update to the SCM. -func gatekeepBuild(c *gin.Context, b *library.Build, r *types.Repo) error { +func gatekeepBuild(c *gin.Context, b *types.Build, r *types.Repo) error { logrus.Debugf("fork PR build %s/%d waiting for approval", r.GetFullName(), b.GetNumber()) b.SetStatus(constants.StatusPendingApproval) diff --git a/api/worker/get.go b/api/worker/get.go index ab277514f..64ce34173 100644 --- a/api/worker/get.go +++ b/api/worker/get.go @@ -9,11 +9,11 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/router/middleware/worker" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" ) // swagger:operation GET /api/v1/workers/{worker} workers GetWorker @@ -57,7 +57,7 @@ func GetWorker(c *gin.Context) { "worker": w.GetHostname(), }).Infof("reading worker %s", w.GetHostname()) - rBs := []*library.Build{} + rBs := []*types.Build{} for _, b := range w.GetRunningBuilds() { build, err := database.FromContext(c).GetBuild(ctx, b.GetID()) diff --git a/api/worker/list.go b/api/worker/list.go index 656745efa..5141335ba 100644 --- a/api/worker/list.go +++ b/api/worker/list.go @@ -11,10 +11,10 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" + "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" ) // swagger:operation GET /api/v1/workers workers ListWorkers @@ -98,7 +98,7 @@ func ListWorkers(c *gin.Context) { } for _, w := range workers { - rBs := []*library.Build{} + rBs := []*types.Build{} for _, b := range w.GetRunningBuilds() { build, err := database.FromContext(c).GetBuild(ctx, b.GetID()) diff --git a/cmd/vela-server/schedule.go b/cmd/vela-server/schedule.go index d069b05a4..ee4a32acd 100644 --- a/cmd/vela-server/schedule.go +++ b/cmd/vela-server/schedule.go @@ -13,6 +13,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "github.com/go-vela/server/api/build" + api "github.com/go-vela/server/api/types" "github.com/go-vela/server/compiler" "github.com/go-vela/server/database" "github.com/go-vela/server/internal" @@ -155,7 +156,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler url := strings.TrimSuffix(r.GetClone(), ".git") - b := new(library.Build) + b := new(api.Build) b.SetAuthor(s.GetCreatedBy()) b.SetBranch(s.GetBranch()) b.SetClone(r.GetClone()) @@ -163,7 +164,7 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler b.SetEvent(constants.EventSchedule) b.SetMessage(fmt.Sprintf("triggered for %s schedule with %s entry", s.GetName(), s.GetEntry())) b.SetRef(fmt.Sprintf("refs/heads/%s", b.GetBranch())) - b.SetRepoID(r.GetID()) + b.SetRepo(r) b.SetSender(s.GetUpdatedBy()) b.SetSource(fmt.Sprintf("%s/tree/%s", url, b.GetBranch())) b.SetStatus(constants.StatusPending) @@ -172,7 +173,6 @@ func processSchedule(ctx context.Context, s *library.Schedule, compiler compiler // schedule form config := build.CompileAndPublishConfig{ Build: b, - Repo: r, Metadata: metadata, BaseErr: "unable to schedule build", Source: "schedule", diff --git a/compiler/engine.go b/compiler/engine.go index 137d9000a..3079148d4 100644 --- a/compiler/engine.go +++ b/compiler/engine.go @@ -116,7 +116,7 @@ type Engine interface { // WithBuild defines a function that sets // the library build type in the Engine. - WithBuild(*library.Build) Engine + WithBuild(*api.Build) Engine // WithComment defines a function that sets // the comment in the Engine. WithComment(string) Engine diff --git a/compiler/native/compile.go b/compiler/native/compile.go index d5cb1d49b..c33035149 100644 --- a/compiler/native/compile.go +++ b/compiler/native/compile.go @@ -498,7 +498,7 @@ func errorHandler(resp *http.Response, err error, attempts int) (*http.Response, } // modifyConfig sends the configuration to external http endpoint for modification. -func (c *client) modifyConfig(build *yaml.Build, libraryBuild *library.Build, repo *api.Repo) (*yaml.Build, error) { +func (c *client) modifyConfig(build *yaml.Build, libraryBuild *api.Build, repo *api.Repo) (*yaml.Build, error) { // create request to send to endpoint data, err := yml.Marshal(build) if err != nil { diff --git a/compiler/native/compile_test.go b/compiler/native/compile_test.go index 86db5f595..ed9563045 100644 --- a/compiler/native/compile_test.go +++ b/compiler/native/compile_test.go @@ -21,7 +21,6 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/internal" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" "github.com/go-vela/types/raw" "github.com/go-vela/types/yaml" @@ -302,7 +301,7 @@ func TestNative_Compile_StagesPipeline_Modification(t *testing.T) { type args struct { endpoint string - libraryBuild *library.Build + libraryBuild *api.Build repo *api.Repo } @@ -312,12 +311,12 @@ func TestNative_Compile_StagesPipeline_Modification(t *testing.T) { wantErr bool }{ {"bad url", args{ - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: "bad", }, true}, {"invalid return", args{ - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: fmt.Sprintf("%s/%s", s.URL, "config/bad"), }, true}, @@ -331,7 +330,7 @@ func TestNative_Compile_StagesPipeline_Modification(t *testing.T) { Endpoint: tt.args.endpoint, }, repo: &api.Repo{Name: &author}, - build: &library.Build{Author: &name, Number: &number}, + build: &api.Build{Author: &name, Number: &number}, } _, _, err := compiler.Compile(yaml) if (err != nil) != tt.wantErr { @@ -370,7 +369,7 @@ func TestNative_Compile_StepsPipeline_Modification(t *testing.T) { type args struct { endpoint string - libraryBuild *library.Build + libraryBuild *api.Build repo *api.Repo } @@ -380,12 +379,12 @@ func TestNative_Compile_StepsPipeline_Modification(t *testing.T) { wantErr bool }{ {"bad url", args{ - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: "bad", }, true}, {"invalid return", args{ - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: fmt.Sprintf("%s/%s", s.URL, "config/bad"), }, true}, @@ -1846,7 +1845,7 @@ func TestNative_Compile_NoStepsorStages(t *testing.T) { } compiler.repo = &api.Repo{Name: &author} - compiler.build = &library.Build{Author: &name, Number: &number} + compiler.build = &api.Build{Author: &name, Number: &number} got, _, err := compiler.Compile(yaml) if err == nil { @@ -1878,7 +1877,7 @@ func TestNative_Compile_StepsandStages(t *testing.T) { } compiler.repo = &api.Repo{Name: &author} - compiler.build = &library.Build{Author: &name, Number: &number} + compiler.build = &api.Build{Author: &name, Number: &number} got, _, err := compiler.Compile(yaml) if err == nil { @@ -2079,7 +2078,7 @@ func Test_client_modifyConfig(t *testing.T) { type args struct { endpoint string build *yaml.Build - libraryBuild *library.Build + libraryBuild *api.Build repo *api.Repo } @@ -2091,37 +2090,37 @@ func Test_client_modifyConfig(t *testing.T) { }{ {"unmodified", args{ build: want, - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: fmt.Sprintf("%s/%s", s.URL, "config/unmodified"), }, want, false}, {"modified", args{ build: want, - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: fmt.Sprintf("%s/%s", s.URL, "config/modified"), }, want2, false}, {"invalid endpoint", args{ build: want, - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: "bad", }, nil, true}, {"unauthorized endpoint", args{ build: want, - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: fmt.Sprintf("%s/%s", s.URL, "config/unauthorized"), }, nil, true}, {"timeout endpoint", args{ build: want, - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: fmt.Sprintf("%s/%s", s.URL, "config/timeout"), }, nil, true}, {"empty payload", args{ build: want, - libraryBuild: &library.Build{Number: &number, Author: &author}, + libraryBuild: &api.Build{Number: &number, Author: &author}, repo: &api.Repo{Name: &name}, endpoint: fmt.Sprintf("%s/%s", s.URL, "config/empty"), }, nil, true}, diff --git a/compiler/native/environment.go b/compiler/native/environment.go index 8b7972877..1d0666e43 100644 --- a/compiler/native/environment.go +++ b/compiler/native/environment.go @@ -282,7 +282,7 @@ func appendMap(originalMap, otherMap map[string]string) map[string]string { } // helper function that creates the standard set of environment variables for a pipeline. -func environment(b *library.Build, m *internal.Metadata, r *api.Repo, u *api.User) map[string]string { +func environment(b *api.Build, m *internal.Metadata, r *api.Repo, u *api.User) map[string]string { // set default workspace workspace := constants.WorkspaceDefault notImplemented := "TODO" diff --git a/compiler/native/environment_test.go b/compiler/native/environment_test.go index e41e02be4..1e090dad1 100644 --- a/compiler/native/environment_test.go +++ b/compiler/native/environment_test.go @@ -13,7 +13,6 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/internal" - "github.com/go-vela/types/library" "github.com/go-vela/types/raw" "github.com/go-vela/types/yaml" ) @@ -577,7 +576,7 @@ func TestNative_environment(t *testing.T) { tests := []struct { w string - b *library.Build + b *api.Build m *internal.Metadata r *api.Repo u *api.User @@ -586,7 +585,7 @@ func TestNative_environment(t *testing.T) { // push { w: workspace, - b: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &push, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &str, BaseRef: &str}, + b: &api.Build{ID: &num64, Repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, Number: &num, Parent: &num, Event: &push, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &str, BaseRef: &str}, m: &internal.Metadata{Database: &internal.Database{Driver: str, Host: str}, Queue: &internal.Queue{Channel: str, Driver: str, Host: str}, Source: &internal.Source{Driver: str, Host: str}, Vela: &internal.Vela{Address: str, WebAddress: str}}, r: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, u: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, @@ -595,7 +594,7 @@ func TestNative_environment(t *testing.T) { // tag { w: workspace, - b: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &tag, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &tagref, BaseRef: &str}, + b: &api.Build{ID: &num64, Repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, Number: &num, Parent: &num, Event: &tag, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &tagref, BaseRef: &str}, m: &internal.Metadata{Database: &internal.Database{Driver: str, Host: str}, Queue: &internal.Queue{Channel: str, Driver: str, Host: str}, Source: &internal.Source{Driver: str, Host: str}, Vela: &internal.Vela{Address: str, WebAddress: str}}, r: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, u: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, @@ -604,7 +603,7 @@ func TestNative_environment(t *testing.T) { // pull_request { w: workspace, - b: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &pull, EventAction: &pullact, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &pullref, BaseRef: &str}, + b: &api.Build{ID: &num64, Repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, Number: &num, Parent: &num, Event: &pull, EventAction: &pullact, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &pullref, BaseRef: &str}, m: &internal.Metadata{Database: &internal.Database{Driver: str, Host: str}, Queue: &internal.Queue{Channel: str, Driver: str, Host: str}, Source: &internal.Source{Driver: str, Host: str}, Vela: &internal.Vela{Address: str, WebAddress: str}}, r: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, u: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, @@ -613,7 +612,7 @@ func TestNative_environment(t *testing.T) { // deployment { w: workspace, - b: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &deploy, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &target, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &pullref, BaseRef: &str}, + b: &api.Build{ID: &num64, Repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, Number: &num, Parent: &num, Event: &deploy, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &target, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &pullref, BaseRef: &str}, m: &internal.Metadata{Database: &internal.Database{Driver: str, Host: str}, Queue: &internal.Queue{Channel: str, Driver: str, Host: str}, Source: &internal.Source{Driver: str, Host: str}, Vela: &internal.Vela{Address: str, WebAddress: str}}, r: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, u: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, @@ -690,7 +689,7 @@ func Test_client_EnvironmentBuild(t *testing.T) { target := "production" type fields struct { - build *library.Build + build *api.Build metadata *internal.Metadata repo *api.Repo user *api.User @@ -702,27 +701,27 @@ func Test_client_EnvironmentBuild(t *testing.T) { want map[string]string }{ {"push", fields{ - build: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &push, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &str, BaseRef: &str}, + build: &api.Build{ID: &num64, Repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, Number: &num, Parent: &num, Event: &push, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &str, BaseRef: &str}, metadata: &internal.Metadata{Database: &internal.Database{Driver: str, Host: str}, Queue: &internal.Queue{Channel: str, Driver: str, Host: str}, Source: &internal.Source{Driver: str, Host: str}, Vela: &internal.Vela{Address: str, WebAddress: str}}, repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, user: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, }, map[string]string{"BUILD_AUTHOR": "foo", "BUILD_AUTHOR_EMAIL": "", "BUILD_BASE_REF": "foo", "BUILD_BRANCH": "foo", "BUILD_CHANNEL": "foo", "BUILD_CLONE": "foo", "BUILD_COMMIT": "foo", "BUILD_CREATED": "1", "BUILD_ENQUEUED": "1", "BUILD_EVENT": "push", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "foo", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_EVENTS": "", "REPOSITORY_BRANCH": "foo", "REPOSITORY_CLONE": "foo", "REPOSITORY_FULL_NAME": "foo", "REPOSITORY_LINK": "foo", "REPOSITORY_NAME": "foo", "REPOSITORY_ORG": "foo", "REPOSITORY_PRIVATE": "false", "REPOSITORY_TIMEOUT": "1", "REPOSITORY_TRUSTED": "false", "REPOSITORY_VISIBILITY": "foo", "VELA": "true", "VELA_ADDR": "foo", "VELA_BUILD_APPROVED_AT": "0", "VELA_BUILD_APPROVED_BY": "", "VELA_BUILD_AUTHOR": "foo", "VELA_BUILD_AUTHOR_EMAIL": "", "VELA_BUILD_BASE_REF": "foo", "VELA_BUILD_BRANCH": "foo", "VELA_BUILD_CHANNEL": "foo", "VELA_BUILD_CLONE": "foo", "VELA_BUILD_COMMIT": "foo", "VELA_BUILD_CREATED": "1", "VELA_BUILD_DISTRIBUTION": "", "VELA_BUILD_ENQUEUED": "1", "VELA_BUILD_EVENT": "push", "VELA_BUILD_EVENT_ACTION": "", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "1", "VELA_BUILD_REF": "foo", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DISTRIBUTION": "TODO", "VELA_HOST": "foo", "VELA_NETRC_MACHINE": "foo", "VELA_NETRC_PASSWORD": "foo", "VELA_NETRC_USERNAME": "x-oauth-basic", "VELA_QUEUE": "foo", "VELA_REPO_ACTIVE": "false", "VELA_REPO_ALLOW_EVENTS": "", "VELA_REPO_APPROVE_BUILD": "", "VELA_REPO_OWNER": "foo", "VELA_REPO_BRANCH": "foo", "VELA_REPO_BUILD_LIMIT": "1", "VELA_REPO_CLONE": "foo", "VELA_REPO_FULL_NAME": "foo", "VELA_REPO_LINK": "foo", "VELA_REPO_NAME": "foo", "VELA_REPO_ORG": "foo", "VELA_REPO_PIPELINE_TYPE": "", "VELA_REPO_PRIVATE": "false", "VELA_REPO_TIMEOUT": "1", "VELA_REPO_TOPICS": "cloud,security", "VELA_REPO_TRUSTED": "false", "VELA_REPO_VISIBILITY": "foo", "VELA_RUNTIME": "TODO", "VELA_SOURCE": "foo", "VELA_USER_ACTIVE": "false", "VELA_USER_ADMIN": "false", "VELA_USER_FAVORITES": "[]", "VELA_USER_NAME": "foo", "VELA_VERSION": "TODO", "VELA_WORKSPACE": "/vela/src/foo/foo/foo"}}, {"tag", fields{ - build: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &tag, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &tagref, BaseRef: &str}, + build: &api.Build{ID: &num64, Repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, Number: &num, Parent: &num, Event: &tag, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &tagref, BaseRef: &str}, metadata: &internal.Metadata{Database: &internal.Database{Driver: str, Host: str}, Queue: &internal.Queue{Channel: str, Driver: str, Host: str}, Source: &internal.Source{Driver: str, Host: str}, Vela: &internal.Vela{Address: str, WebAddress: str}}, repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, user: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, }, map[string]string{"BUILD_AUTHOR": "foo", "BUILD_AUTHOR_EMAIL": "", "BUILD_BASE_REF": "foo", "BUILD_BRANCH": "foo", "BUILD_CHANNEL": "foo", "BUILD_CLONE": "foo", "BUILD_COMMIT": "foo", "BUILD_CREATED": "1", "BUILD_ENQUEUED": "1", "BUILD_EVENT": "tag", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_REF": "refs/tags/1", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TAG": "1", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_EVENTS": "", "REPOSITORY_BRANCH": "foo", "REPOSITORY_CLONE": "foo", "REPOSITORY_FULL_NAME": "foo", "REPOSITORY_LINK": "foo", "REPOSITORY_NAME": "foo", "REPOSITORY_ORG": "foo", "REPOSITORY_PRIVATE": "false", "REPOSITORY_TIMEOUT": "1", "REPOSITORY_TRUSTED": "false", "REPOSITORY_VISIBILITY": "foo", "VELA": "true", "VELA_ADDR": "foo", "VELA_BUILD_APPROVED_AT": "0", "VELA_BUILD_APPROVED_BY": "", "VELA_BUILD_AUTHOR": "foo", "VELA_BUILD_AUTHOR_EMAIL": "", "VELA_BUILD_BASE_REF": "foo", "VELA_BUILD_BRANCH": "foo", "VELA_BUILD_CHANNEL": "foo", "VELA_BUILD_CLONE": "foo", "VELA_BUILD_COMMIT": "foo", "VELA_BUILD_CREATED": "1", "VELA_BUILD_DISTRIBUTION": "", "VELA_BUILD_ENQUEUED": "1", "VELA_BUILD_EVENT": "tag", "VELA_BUILD_EVENT_ACTION": "", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "1", "VELA_BUILD_REF": "refs/tags/1", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TAG": "1", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DISTRIBUTION": "TODO", "VELA_HOST": "foo", "VELA_NETRC_MACHINE": "foo", "VELA_NETRC_PASSWORD": "foo", "VELA_NETRC_USERNAME": "x-oauth-basic", "VELA_QUEUE": "foo", "VELA_REPO_ACTIVE": "false", "VELA_REPO_ALLOW_EVENTS": "", "VELA_REPO_APPROVE_BUILD": "", "VELA_REPO_OWNER": "foo", "VELA_REPO_BRANCH": "foo", "VELA_REPO_BUILD_LIMIT": "1", "VELA_REPO_CLONE": "foo", "VELA_REPO_FULL_NAME": "foo", "VELA_REPO_LINK": "foo", "VELA_REPO_NAME": "foo", "VELA_REPO_ORG": "foo", "VELA_REPO_PIPELINE_TYPE": "", "VELA_REPO_PRIVATE": "false", "VELA_REPO_TIMEOUT": "1", "VELA_REPO_TOPICS": "cloud,security", "VELA_REPO_TRUSTED": "false", "VELA_REPO_VISIBILITY": "foo", "VELA_RUNTIME": "TODO", "VELA_SOURCE": "foo", "VELA_USER_ACTIVE": "false", "VELA_USER_ADMIN": "false", "VELA_USER_FAVORITES": "[]", "VELA_USER_NAME": "foo", "VELA_VERSION": "TODO", "VELA_WORKSPACE": "/vela/src/foo/foo/foo"}, }, {"pull_request", fields{ - build: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &pull, EventAction: &pullact, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &pullref, BaseRef: &str}, + build: &api.Build{ID: &num64, Repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, Number: &num, Parent: &num, Event: &pull, EventAction: &pullact, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &str, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &pullref, BaseRef: &str}, metadata: &internal.Metadata{Database: &internal.Database{Driver: str, Host: str}, Queue: &internal.Queue{Channel: str, Driver: str, Host: str}, Source: &internal.Source{Driver: str, Host: str}, Vela: &internal.Vela{Address: str, WebAddress: str}}, repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, user: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, }, map[string]string{"BUILD_AUTHOR": "foo", "BUILD_AUTHOR_EMAIL": "", "BUILD_BASE_REF": "foo", "BUILD_BRANCH": "foo", "BUILD_CHANNEL": "foo", "BUILD_CLONE": "foo", "BUILD_COMMIT": "foo", "BUILD_CREATED": "1", "BUILD_ENQUEUED": "1", "BUILD_EVENT": "pull_request", "BUILD_HOST": "", "BUILD_LINK": "", "BUILD_MESSAGE": "foo", "BUILD_NUMBER": "1", "BUILD_PARENT": "1", "BUILD_PULL_REQUEST_NUMBER": "1", "BUILD_REF": "refs/pull/1/head", "BUILD_SENDER": "foo", "BUILD_SOURCE": "foo", "BUILD_STARTED": "1", "BUILD_STATUS": "foo", "BUILD_TITLE": "foo", "BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "CI": "true", "REPOSITORY_ACTIVE": "false", "REPOSITORY_ALLOW_EVENTS": "", "REPOSITORY_BRANCH": "foo", "REPOSITORY_CLONE": "foo", "REPOSITORY_FULL_NAME": "foo", "REPOSITORY_LINK": "foo", "REPOSITORY_NAME": "foo", "REPOSITORY_ORG": "foo", "REPOSITORY_PRIVATE": "false", "REPOSITORY_TIMEOUT": "1", "REPOSITORY_TRUSTED": "false", "REPOSITORY_VISIBILITY": "foo", "VELA": "true", "VELA_ADDR": "foo", "VELA_BUILD_APPROVED_AT": "0", "VELA_BUILD_APPROVED_BY": "", "VELA_BUILD_AUTHOR": "foo", "VELA_BUILD_AUTHOR_EMAIL": "", "VELA_BUILD_BASE_REF": "foo", "VELA_BUILD_BRANCH": "foo", "VELA_BUILD_CHANNEL": "foo", "VELA_BUILD_CLONE": "foo", "VELA_BUILD_COMMIT": "foo", "VELA_BUILD_CREATED": "1", "VELA_BUILD_DISTRIBUTION": "", "VELA_BUILD_ENQUEUED": "1", "VELA_BUILD_EVENT": "pull_request", "VELA_BUILD_EVENT_ACTION": "opened", "VELA_BUILD_HOST": "", "VELA_BUILD_LINK": "", "VELA_BUILD_MESSAGE": "foo", "VELA_BUILD_NUMBER": "1", "VELA_BUILD_PARENT": "1", "VELA_BUILD_PULL_REQUEST": "1", "VELA_BUILD_REF": "refs/pull/1/head", "VELA_BUILD_RUNTIME": "", "VELA_BUILD_SENDER": "foo", "VELA_BUILD_SOURCE": "foo", "VELA_BUILD_STARTED": "1", "VELA_BUILD_STATUS": "foo", "VELA_BUILD_TITLE": "foo", "VELA_BUILD_WORKSPACE": "/vela/src/foo/foo/foo", "VELA_CHANNEL": "foo", "VELA_DATABASE": "foo", "VELA_DISTRIBUTION": "TODO", "VELA_HOST": "foo", "VELA_NETRC_MACHINE": "foo", "VELA_NETRC_PASSWORD": "foo", "VELA_NETRC_USERNAME": "x-oauth-basic", "VELA_PULL_REQUEST": "1", "VELA_PULL_REQUEST_SOURCE": "", "VELA_PULL_REQUEST_TARGET": "foo", "VELA_QUEUE": "foo", "VELA_REPO_ACTIVE": "false", "VELA_REPO_ALLOW_EVENTS": "", "VELA_REPO_APPROVE_BUILD": "", "VELA_REPO_OWNER": "foo", "VELA_REPO_BRANCH": "foo", "VELA_REPO_BUILD_LIMIT": "1", "VELA_REPO_CLONE": "foo", "VELA_REPO_FULL_NAME": "foo", "VELA_REPO_LINK": "foo", "VELA_REPO_NAME": "foo", "VELA_REPO_ORG": "foo", "VELA_REPO_PIPELINE_TYPE": "", "VELA_REPO_PRIVATE": "false", "VELA_REPO_TIMEOUT": "1", "VELA_REPO_TOPICS": "cloud,security", "VELA_REPO_TRUSTED": "false", "VELA_REPO_VISIBILITY": "foo", "VELA_RUNTIME": "TODO", "VELA_SOURCE": "foo", "VELA_USER_ACTIVE": "false", "VELA_USER_ADMIN": "false", "VELA_USER_FAVORITES": "[]", "VELA_USER_NAME": "foo", "VELA_VERSION": "TODO", "VELA_WORKSPACE": "/vela/src/foo/foo/foo"}, }, {"deployment", fields{ - build: &library.Build{ID: &num64, RepoID: &num64, Number: &num, Parent: &num, Event: &deploy, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &target, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &pullref, BaseRef: &str}, + build: &api.Build{ID: &num64, Repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, Number: &num, Parent: &num, Event: &deploy, Status: &str, Error: &str, Enqueued: &num64, Created: &num64, Started: &num64, Finished: &num64, Deploy: &target, Clone: &str, Source: &str, Title: &str, Message: &str, Commit: &str, Sender: &str, Author: &str, Branch: &str, Ref: &pullref, BaseRef: &str}, metadata: &internal.Metadata{Database: &internal.Database{Driver: str, Host: str}, Queue: &internal.Queue{Channel: str, Driver: str, Host: str}, Source: &internal.Source{Driver: str, Host: str}, Vela: &internal.Vela{Address: str, WebAddress: str}}, repo: &api.Repo{ID: &num64, Owner: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, Org: &str, Name: &str, FullName: &str, Link: &str, Clone: &str, Branch: &str, Topics: &topics, BuildLimit: &num64, Timeout: &num64, Visibility: &str, Private: &booL, Trusted: &booL, Active: &booL}, user: &api.User{ID: &num64, Name: &str, Token: &str, Active: &booL, Admin: &booL}, diff --git a/compiler/native/expand_test.go b/compiler/native/expand_test.go index c43eb14bd..cf6f3927f 100644 --- a/compiler/native/expand_test.go +++ b/compiler/native/expand_test.go @@ -14,7 +14,6 @@ import ( "github.com/urfave/cli/v2" api "github.com/go-vela/server/api/types" - "github.com/go-vela/types/library" "github.com/go-vela/types/pipeline" "github.com/go-vela/types/raw" "github.com/go-vela/types/yaml" @@ -763,7 +762,7 @@ func TestNative_ExpandSteps_TemplateCallTemplate(t *testing.T) { set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) - testBuild := new(library.Build) + testBuild := new(api.Build) testBuild.SetID(1) testBuild.SetCommit("123abc456def") @@ -931,7 +930,7 @@ func TestNative_ExpandSteps_TemplateCallTemplate_CircularFail(t *testing.T) { set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) - testBuild := new(library.Build) + testBuild := new(api.Build) testBuild.SetID(1) testBuild.SetCommit("123abc456def") @@ -1017,7 +1016,7 @@ func TestNative_ExpandSteps_CallTemplateWithRenderInline(t *testing.T) { set.Int("max-template-depth", 5, "doc") c := cli.NewContext(nil, set, nil) - testBuild := new(library.Build) + testBuild := new(api.Build) testBuild.SetID(1) testBuild.SetCommit("123abc456def") diff --git a/compiler/native/native.go b/compiler/native/native.go index b92cfd2ea..026341063 100644 --- a/compiler/native/native.go +++ b/compiler/native/native.go @@ -13,7 +13,6 @@ import ( "github.com/go-vela/server/compiler/registry" "github.com/go-vela/server/compiler/registry/github" "github.com/go-vela/server/internal" - "github.com/go-vela/types/library" ) type ModificationConfig struct { @@ -32,7 +31,7 @@ type client struct { TemplateDepth int StarlarkExecLimit uint64 - build *library.Build + build *api.Build comment string commit string files []string @@ -124,7 +123,7 @@ func (c *client) Duplicate() compiler.Engine { } // WithBuild sets the library build type in the Engine. -func (c *client) WithBuild(b *library.Build) compiler.Engine { +func (c *client) WithBuild(b *api.Build) compiler.Engine { if b != nil { c.build = b } diff --git a/compiler/native/native_test.go b/compiler/native/native_test.go index 5e84a6664..835169e5d 100644 --- a/compiler/native/native_test.go +++ b/compiler/native/native_test.go @@ -12,7 +12,6 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/compiler/registry/github" "github.com/go-vela/server/internal" - "github.com/go-vela/types/library" ) func TestNative_New(t *testing.T) { @@ -100,7 +99,7 @@ func TestNative_DuplicateStripBuild(t *testing.T) { c := cli.NewContext(nil, set, nil) id := int64(1) - b := &library.Build{ID: &id} + b := &api.Build{ID: &id} want, _ := New(c) @@ -123,7 +122,7 @@ func TestNative_WithBuild(t *testing.T) { c := cli.NewContext(nil, set, nil) id := int64(1) - b := &library.Build{ID: &id} + b := &api.Build{ID: &id} want, _ := New(c) want.build = b diff --git a/database/build/build.go b/database/build/build.go index 1d1a42d97..0ff9871bd 100644 --- a/database/build/build.go +++ b/database/build/build.go @@ -15,6 +15,8 @@ import ( type ( // config represents the settings required to create the engine that implements the BuildInterface interface. config struct { + // specifies the encryption key to use for the Build engine + EncryptionKey string // specifies to skip creating tables and indexes for the Build engine SkipCreation bool } diff --git a/database/build/build_test.go b/database/build/build_test.go index 5971b5d48..383c0573c 100644 --- a/database/build/build_test.go +++ b/database/build/build_test.go @@ -14,10 +14,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - api "github.com/go-vela/server/api/types" - "github.com/go-vela/types/library" - "github.com/go-vela/types/raw" ) func TestBuild_New(t *testing.T) { @@ -116,6 +112,34 @@ func TestBuild_New(t *testing.T) { } } +// TEST RESOURCES + +// This will be used with the github.com/DATA-DOG/go-sqlmock library to compare values +// that are otherwise not easily compared. These typically would be values generated +// before adding or updating them in the database. +// +// https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime +type AnyArgument struct{} + +// Match satisfies sqlmock.Argument interface. +func (a AnyArgument) Match(_ driver.Value) bool { + return true +} + +// NowTimestamp is used to test whether timestamps get updated correctly to the current time with lenience. +type NowTimestamp struct{} + +// Match satisfies sqlmock.Argument interface. +func (t NowTimestamp) Match(v driver.Value) bool { + ts, ok := v.(int64) + if !ok { + return false + } + now := time.Now().Unix() + + return now-ts < 10 +} + // testPostgres is a helper function to create a Postgres engine for testing. func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { // create the new mock sql database @@ -148,6 +172,7 @@ func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { WithClient(_postgres), WithLogger(logrus.NewEntry(logrus.StandardLogger())), WithSkipCreation(false), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), ) if err != nil { t.Errorf("unable to create new postgres build engine: %v", err) @@ -171,6 +196,7 @@ func testSqlite(t *testing.T) *engine { WithClient(_sqlite), WithLogger(logrus.NewEntry(logrus.StandardLogger())), WithSkipCreation(false), + WithEncryptionKey("A1B2C3D4E5G6H7I8J9K0LMNOPQRSTUVW"), ) if err != nil { t.Errorf("unable to create new sqlite build engine: %v", err) @@ -178,114 +204,3 @@ func testSqlite(t *testing.T) *engine { return _engine } - -// testBuild is a test helper function to create a library -// Build type with all fields set to their zero values. -func testBuild() *library.Build { - return &library.Build{ - ID: new(int64), - RepoID: new(int64), - PipelineID: new(int64), - Number: new(int), - Parent: new(int), - Event: new(string), - EventAction: new(string), - Status: new(string), - Error: new(string), - Enqueued: new(int64), - Created: new(int64), - Started: new(int64), - Finished: new(int64), - Deploy: new(string), - DeployNumber: new(int64), - Clone: new(string), - Source: new(string), - Title: new(string), - Message: new(string), - Commit: new(string), - Sender: new(string), - Author: new(string), - Email: new(string), - Link: new(string), - Branch: new(string), - Ref: new(string), - BaseRef: new(string), - HeadRef: new(string), - Host: new(string), - Runtime: new(string), - Distribution: new(string), - ApprovedAt: new(int64), - ApprovedBy: new(string), - } -} - -// testDeployment is a test helper function to create a library -// Repo type with all fields set to their zero values. -func testDeployment() *library.Deployment { - builds := []*library.Build{} - return &library.Deployment{ - ID: new(int64), - RepoID: new(int64), - Number: new(int64), - URL: new(string), - Commit: new(string), - Ref: new(string), - Task: new(string), - Target: new(string), - Description: new(string), - Payload: new(raw.StringSliceMap), - CreatedAt: new(int64), - CreatedBy: new(string), - Builds: builds, - } -} - -// testRepo is a test helper function to create a library -// Repo type with all fields set to their zero values. -func testRepo() *api.Repo { - return &api.Repo{ - ID: new(int64), - BuildLimit: new(int64), - Timeout: new(int64), - Counter: new(int), - PipelineType: new(string), - Hash: new(string), - Org: new(string), - Name: new(string), - FullName: new(string), - Link: new(string), - Clone: new(string), - Branch: new(string), - Visibility: new(string), - PreviousName: new(string), - Private: new(bool), - Trusted: new(bool), - Active: new(bool), - } -} - -// This will be used with the github.com/DATA-DOG/go-sqlmock library to compare values -// that are otherwise not easily compared. These typically would be values generated -// before adding or updating them in the database. -// -// https://github.com/DATA-DOG/go-sqlmock#matching-arguments-like-timetime -type AnyArgument struct{} - -// Match satisfies sqlmock.Argument interface. -func (a AnyArgument) Match(_ driver.Value) bool { - return true -} - -// NowTimestamp is used to test whether timestamps get updated correctly to the current time with lenience. -type NowTimestamp struct{} - -// Match satisfies sqlmock.Argument interface. -func (t NowTimestamp) Match(v driver.Value) bool { - ts, ok := v.(int64) - if !ok { - return false - } - now := time.Now().Unix() - - return now-ts < 10 -} diff --git a/database/build/clean.go b/database/build/clean.go index 4559bac5f..5c239a57e 100644 --- a/database/build/clean.go +++ b/database/build/clean.go @@ -8,21 +8,21 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // CleanBuilds updates builds to an error with a provided message with a created timestamp prior to a defined moment. func (e *engine) CleanBuilds(ctx context.Context, msg string, before int64) (int64, error) { logrus.Tracef("cleaning pending or running builds in the database created prior to %d", before) - b := new(library.Build) + b := new(api.Build) b.SetStatus(constants.StatusError) b.SetError(msg) b.SetFinished(time.Now().UTC().Unix()) - build := database.BuildFromLibrary(b) + build := types.BuildFromAPI(b) // send query to the database result := e.client. diff --git a/database/build/clean_test.go b/database/build/clean_test.go index 28eb29195..179dd2fb8 100644 --- a/database/build/clean_test.go +++ b/database/build/clean_test.go @@ -8,35 +8,56 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_CleanBuilds(t *testing.T) { // setup types - _buildOne := testBuild() + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + _repo.SetTopics([]string{}) + _repo.SetAllowEvents(api.NewEventsFromMask(1)) + + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo.SetOwner(_owner) + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repo) _buildOne.SetNumber(1) _buildOne.SetCreated(1) _buildOne.SetStatus("pending") - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repo) _buildTwo.SetNumber(2) _buildTwo.SetCreated(2) _buildTwo.SetStatus("running") // setup types - _buildThree := testBuild() + _buildThree := testutils.APIBuild() _buildThree.SetID(3) - _buildThree.SetRepoID(1) + _buildThree.SetRepo(_repo) _buildThree.SetNumber(3) _buildThree.SetCreated(1) _buildThree.SetStatus("success") - _buildFour := testBuild() + _buildFour := testutils.APIBuild() _buildFour.SetID(4) - _buildFour.SetRepoID(1) + _buildFour.SetRepo(_repo) _buildFour.SetNumber(4) _buildFour.SetCreated(5) _buildFour.SetStatus("running") diff --git a/database/build/count_deployment_test.go b/database/build/count_deployment_test.go index 6b4f83823..64fbbbbae 100644 --- a/database/build/count_deployment_test.go +++ b/database/build/count_deployment_test.go @@ -8,25 +8,46 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_CountBuildsForDeployment(t *testing.T) { // setup types - _buildOne := testBuild() + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetPipelineType("yaml") + _repo.SetTopics([]string{}) + _repo.SetAllowEvents(api.NewEventsFromMask(1)) + + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo.SetOwner(_owner) + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repo) _buildOne.SetNumber(1) _buildOne.SetDeployPayload(nil) _buildOne.SetSource("https://github.com/github/octocat/deployments/1") - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repo) _buildTwo.SetNumber(2) _buildTwo.SetDeployPayload(nil) _buildTwo.SetSource("https://github.com/github/octocat/deployments/1") - _deployment := testDeployment() + _deployment := testutils.APIDeployment() _deployment.SetID(1) _deployment.SetRepoID(1) _deployment.SetURL("https://github.com/github/octocat/deployments/1") diff --git a/database/build/count_org_test.go b/database/build/count_org_test.go index 635e7bd66..546e59678 100644 --- a/database/build/count_org_test.go +++ b/database/build/count_org_test.go @@ -9,29 +9,21 @@ import ( "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/server/database/repo" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) func TestBuild_Engine_CountBuildsForOrg(t *testing.T) { // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetDeployPayload(nil) - _buildOne.SetEvent("push") - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(2) - _buildTwo.SetNumber(2) - _buildTwo.SetDeployPayload(nil) - _buildTwo.SetEvent("push") + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") - _repoOne := testRepo() + _repoOne := testutils.APIRepo() _repoOne.SetID(1) - _repoOne.GetOwner().SetID(1) + _repoOne.SetOwner(_owner) _repoOne.SetHash("baz") _repoOne.SetOrg("foo") _repoOne.SetName("bar") @@ -40,9 +32,9 @@ func TestBuild_Engine_CountBuildsForOrg(t *testing.T) { _repoOne.SetPipelineType("yaml") _repoOne.SetTopics([]string{}) - _repoTwo := testRepo() + _repoTwo := testutils.APIRepo() _repoTwo.SetID(2) - _repoTwo.GetOwner().SetID(1) + _repoTwo.SetOwner(_owner) _repoTwo.SetHash("bar") _repoTwo.SetOrg("foo") _repoTwo.SetName("baz") @@ -51,6 +43,20 @@ func TestBuild_Engine_CountBuildsForOrg(t *testing.T) { _repoTwo.SetPipelineType("yaml") _repoTwo.SetTopics([]string{}) + _buildOne := testutils.APIBuild() + _buildOne.SetID(1) + _buildOne.SetRepo(_repoOne) + _buildOne.SetNumber(1) + _buildOne.SetDeployPayload(nil) + _buildOne.SetEvent("push") + + _buildTwo := testutils.APIBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepo(_repoTwo) + _buildTwo.SetNumber(2) + _buildTwo.SetDeployPayload(nil) + _buildTwo.SetEvent("push") + _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -77,17 +83,17 @@ func TestBuild_Engine_CountBuildsForOrg(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&repo.Repo{}) + err = _sqlite.client.AutoMigrate(&types.Repo{}) if err != nil { t.Errorf("unable to create repo table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableRepo).Create(repo.FromAPI(_repoOne)).Error + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repoOne)).Error if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableRepo).Create(repo.FromAPI(_repoTwo)).Error + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repoTwo)).Error if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } diff --git a/database/build/count_repo_test.go b/database/build/count_repo_test.go index edbb77816..77bbc69d6 100644 --- a/database/build/count_repo_test.go +++ b/database/build/count_repo_test.go @@ -8,23 +8,18 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_CountBuildsForRepo(t *testing.T) { // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetDeployPayload(nil) - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) - _buildTwo.SetNumber(2) - _buildTwo.SetDeployPayload(nil) + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetHash("baz") @@ -33,6 +28,18 @@ func TestBuild_Engine_CountBuildsForRepo(t *testing.T) { _repo.SetFullName("foo/bar") _repo.SetVisibility("public") + _buildOne := testutils.APIBuild() + _buildOne.SetID(1) + _buildOne.SetRepo(_repo) + _buildOne.SetNumber(1) + _buildOne.SetDeployPayload(nil) + + _buildTwo := testutils.APIBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepo(_repo) + _buildTwo.SetNumber(2) + _buildTwo.SetDeployPayload(nil) + _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() diff --git a/database/build/count_status_test.go b/database/build/count_status_test.go index cea339953..6fe707142 100644 --- a/database/build/count_status_test.go +++ b/database/build/count_status_test.go @@ -8,20 +8,36 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_CountBuildsForStatus(t *testing.T) { // setup types - _buildOne := testBuild() + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.GetOwner().SetID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repo) _buildOne.SetNumber(1) _buildOne.SetDeployPayload(nil) _buildOne.SetStatus("running") - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repo) _buildTwo.SetNumber(2) _buildTwo.SetDeployPayload(nil) _buildTwo.SetStatus("running") diff --git a/database/build/count_test.go b/database/build/count_test.go index bdcc57078..a1d7717ce 100644 --- a/database/build/count_test.go +++ b/database/build/count_test.go @@ -8,19 +8,35 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_CountBuilds(t *testing.T) { // setup types - _buildOne := testBuild() + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.GetOwner().SetID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repo) _buildOne.SetNumber(1) _buildOne.SetDeployPayload(nil) - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repo) _buildTwo.SetNumber(2) _buildTwo.SetDeployPayload(nil) diff --git a/database/build/create.go b/database/build/create.go index 1c04548b5..0ba65aad5 100644 --- a/database/build/create.go +++ b/database/build/create.go @@ -8,25 +8,19 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // CreateBuild creates a new build in the database. -func (e *engine) CreateBuild(ctx context.Context, b *library.Build) (*library.Build, error) { +func (e *engine) CreateBuild(ctx context.Context, b *api.Build) (*api.Build, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("creating build %d in the database", b.GetNumber()) - // cast the library type to database type - // - // https://pkg.go.dev/github.com/go-vela/types/database#BuildFromLibrary - build := database.BuildFromLibrary(b) + build := types.BuildFromAPI(b) - // validate the necessary fields are populated - // - // https://pkg.go.dev/github.com/go-vela/types/database#Build.Validate err := build.Validate() if err != nil { return nil, err @@ -36,7 +30,13 @@ func (e *engine) CreateBuild(ctx context.Context, b *library.Build) (*library.Bu build = build.Crop() // send query to the database - result := e.client.Table(constants.TableBuild).Create(build) + err = e.client.Table(constants.TableBuild).Create(build).Error + if err != nil { + return nil, err + } + + result := build.ToAPI() + result.SetRepo(b.GetRepo()) - return build.ToLibrary(), result.Error + return result, nil } diff --git a/database/build/create_test.go b/database/build/create_test.go index 86e9b8751..83b6f5a2c 100644 --- a/database/build/create_test.go +++ b/database/build/create_test.go @@ -8,13 +8,29 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_CreateBuild(t *testing.T) { // setup types - _build := testBuild() + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.GetOwner().SetID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(_repo) _build.SetNumber(1) _build.SetDeployPayload(nil) diff --git a/database/build/delete.go b/database/build/delete.go index 78bc11f71..b2bff7795 100644 --- a/database/build/delete.go +++ b/database/build/delete.go @@ -7,21 +7,18 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // DeleteBuild deletes an existing build from the database. -func (e *engine) DeleteBuild(ctx context.Context, b *library.Build) error { +func (e *engine) DeleteBuild(ctx context.Context, b *api.Build) error { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("deleting build %d from the database", b.GetNumber()) - // cast the library type to database type - // - // https://pkg.go.dev/github.com/go-vela/types/database#BuildFromLibrary - build := database.BuildFromLibrary(b) + build := types.BuildFromAPI(b) // send query to the database return e.client. diff --git a/database/build/delete_test.go b/database/build/delete_test.go index 33ca6e3d6..7a7b21ed0 100644 --- a/database/build/delete_test.go +++ b/database/build/delete_test.go @@ -7,13 +7,29 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_DeleteBuild(t *testing.T) { // setup types - _build := testBuild() + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.GetOwner().SetID(1) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(_repo) _build.SetNumber(1) _build.SetDeployPayload(nil) diff --git a/database/build/get.go b/database/build/get.go index 02df1d42a..a780b1721 100644 --- a/database/build/get.go +++ b/database/build/get.go @@ -5,21 +5,23 @@ package build import ( "context" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // GetBuild gets a build by ID from the database. -func (e *engine) GetBuild(ctx context.Context, id int64) (*library.Build, error) { +func (e *engine) GetBuild(ctx context.Context, id int64) (*api.Build, error) { e.logger.Tracef("getting build %d from the database", id) // variable to store query results - b := new(database.Build) + b := new(types.Build) // send query to the database and store result in variable err := e.client. Table(constants.TableBuild). + Preload("Repo"). + Preload("Repo.Owner"). Where("id = ?", id). Take(b). Error @@ -27,5 +29,10 @@ func (e *engine) GetBuild(ctx context.Context, id int64) (*library.Build, error) return nil, err } - return b.ToLibrary(), nil + err = b.Repo.Decrypt(e.config.EncryptionKey) + if err != nil { + e.logger.Errorf("unable to decrypt repo: %v", err) + } + + return b.ToAPI(), nil } diff --git a/database/build/get_repo.go b/database/build/get_repo.go index 3b3ae9998..8a13009c2 100644 --- a/database/build/get_repo.go +++ b/database/build/get_repo.go @@ -8,13 +8,12 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // GetBuildForRepo gets a build by repo ID and number from the database. -func (e *engine) GetBuildForRepo(ctx context.Context, r *api.Repo, number int) (*library.Build, error) { +func (e *engine) GetBuildForRepo(ctx context.Context, r *api.Repo, number int) (*api.Build, error) { e.logger.WithFields(logrus.Fields{ "build": number, "org": r.GetOrg(), @@ -22,11 +21,13 @@ func (e *engine) GetBuildForRepo(ctx context.Context, r *api.Repo, number int) ( }).Tracef("getting build %s/%d from the database", r.GetFullName(), number) // variable to store query results - b := new(database.Build) + b := new(types.Build) // send query to the database and store result in variable err := e.client. Table(constants.TableBuild). + Preload("Repo"). + Preload("Repo.Owner"). Where("repo_id = ?", r.GetID()). Where("number = ?", number). Take(b). @@ -35,5 +36,10 @@ func (e *engine) GetBuildForRepo(ctx context.Context, r *api.Repo, number int) ( return nil, err } - return b.ToLibrary(), nil + err = b.Repo.Decrypt(e.config.EncryptionKey) + if err != nil { + e.logger.Errorf("unable to decrypt repo %s/%s: %v", r.GetOrg(), r.GetName(), err) + } + + return b.ToAPI(), nil } diff --git a/database/build/get_repo_test.go b/database/build/get_repo_test.go index 906f35aee..e2db55642 100644 --- a/database/build/get_repo_test.go +++ b/database/build/get_repo_test.go @@ -4,31 +4,42 @@ package build import ( "context" - "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" + "github.com/google/go-cmp/cmp" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" + "github.com/go-vela/types/constants" ) func TestBuild_Engine_GetBuildForRepo(t *testing.T) { // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployNumber(0) - _build.SetDeployPayload(nil) + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) - _repo.GetOwner().SetID(1) + _repo.SetOwner(_owner) _repo.SetHash("baz") _repo.SetOrg("foo") _repo.SetName("bar") _repo.SetFullName("foo/bar") _repo.SetVisibility("public") + _repo.SetAllowEvents(api.NewEventsFromMask(1)) + _repo.SetPipelineType(constants.PipelineTypeYAML) + _repo.SetTopics([]string{}) + + _build := testutils.APIBuild() + _build.SetID(1) + _build.SetRepo(_repo) + _build.SetNumber(1) + _build.SetDeployNumber(0) + _build.SetDeployPayload(nil) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -38,8 +49,18 @@ func TestBuild_Engine_GetBuildForRepo(t *testing.T) { []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "event_action", "status", "error", "enqueued", "created", "started", "finished", "deploy", "deploy_number", "deploy_payload", "clone", "source", "title", "message", "commit", "sender", "author", "email", "link", "branch", "ref", "base_ref", "head_ref", "host", "runtime", "distribution", "timestamp"}). AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", 0, nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + _repoRows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows := sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "builds" WHERE repo_id = $1 AND number = $2 LIMIT $3`).WithArgs(1, 1, 1).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" = $1`).WithArgs(1).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -49,12 +70,32 @@ func TestBuild_Engine_GetBuildForRepo(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } + err = _sqlite.client.AutoMigrate(&types.Repo{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repo)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&types.User{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + // setup tests tests := []struct { failure bool name string database *engine - want *library.Build + want *api.Build }{ { failure: false, @@ -87,8 +128,8 @@ func TestBuild_Engine_GetBuildForRepo(t *testing.T) { t.Errorf("GetBuildForRepo for %s returned err: %v", test.name, err) } - if !reflect.DeepEqual(got, test.want) { - t.Errorf("GetBuildForRepo for %s is %v, want %v", test.name, got, test.want) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("GetBuildForRepo for %s mismatch (-want +got):\n%s", test.name, diff) } }) } diff --git a/database/build/get_test.go b/database/build/get_test.go index 4df407ef7..e4a26d852 100644 --- a/database/build/get_test.go +++ b/database/build/get_test.go @@ -9,14 +9,34 @@ import ( "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" + "github.com/go-vela/types/constants" ) func TestBuild_Engine_GetBuild(t *testing.T) { // setup types - _build := testBuild() + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.SetOwner(_owner) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetAllowEvents(api.NewEventsFromMask(1)) + _repo.SetPipelineType(constants.PipelineTypeYAML) + _repo.SetTopics([]string{}) + + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(_repo) _build.SetNumber(1) _build.SetDeployPayload(nil) @@ -28,8 +48,18 @@ func TestBuild_Engine_GetBuild(t *testing.T) { []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "event_action", "status", "error", "enqueued", "created", "started", "finished", "deploy", "deploy_payload", "clone", "source", "title", "message", "commit", "sender", "author", "email", "link", "branch", "ref", "base_ref", "head_ref", "host", "runtime", "distribution", "approved_at", "approved_by", "timestamp"}). AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0) + _repoRows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows := sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "builds" WHERE id = $1 LIMIT $2`).WithArgs(1, 1).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" = $1`).WithArgs(1).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -39,12 +69,32 @@ func TestBuild_Engine_GetBuild(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } + err = _sqlite.client.AutoMigrate(&types.Repo{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repo)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&types.User{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + // setup tests tests := []struct { failure bool name string database *engine - want *library.Build + want *api.Build }{ { failure: false, diff --git a/database/build/interface.go b/database/build/interface.go index 03c6918b7..01fad378a 100644 --- a/database/build/interface.go +++ b/database/build/interface.go @@ -40,27 +40,27 @@ type BuildInterface interface { // CountBuildsForStatus defines a function that gets the count of builds by status. CountBuildsForStatus(context.Context, string, map[string]interface{}) (int64, error) // CreateBuild defines a function that creates a new build. - CreateBuild(context.Context, *library.Build) (*library.Build, error) + CreateBuild(context.Context, *api.Build) (*api.Build, error) // DeleteBuild defines a function that deletes an existing build. - DeleteBuild(context.Context, *library.Build) error + DeleteBuild(context.Context, *api.Build) error // GetBuild defines a function that gets a build by ID. - GetBuild(context.Context, int64) (*library.Build, error) + GetBuild(context.Context, int64) (*api.Build, error) // GetBuildForRepo defines a function that gets a build by repo ID and number. - GetBuildForRepo(context.Context, *api.Repo, int) (*library.Build, error) + GetBuildForRepo(context.Context, *api.Repo, int) (*api.Build, error) // LastBuildForRepo defines a function that gets the last build ran by repo ID and branch. - LastBuildForRepo(context.Context, *api.Repo, string) (*library.Build, error) + LastBuildForRepo(context.Context, *api.Repo, string) (*api.Build, error) // ListBuilds defines a function that gets a list of all builds. - ListBuilds(context.Context) ([]*library.Build, error) + ListBuilds(context.Context) ([]*api.Build, error) // ListBuildsForOrg defines a function that gets a list of builds by org name. - ListBuildsForOrg(context.Context, string, map[string]interface{}, int, int) ([]*library.Build, int64, error) + ListBuildsForOrg(context.Context, string, map[string]interface{}, int, int) ([]*api.Build, int64, error) // ListBuildsForDashboardRepo defines a function that gets a list of builds based on dashboard filters. - ListBuildsForDashboardRepo(context.Context, *api.Repo, []string, []string) ([]*library.Build, error) + ListBuildsForDashboardRepo(context.Context, *api.Repo, []string, []string) ([]*api.Build, error) // ListBuildsForRepo defines a function that gets a list of builds by repo ID. - ListBuildsForRepo(context.Context, *api.Repo, map[string]interface{}, int64, int64, int, int) ([]*library.Build, int64, error) + ListBuildsForRepo(context.Context, *api.Repo, map[string]interface{}, int64, int64, int, int) ([]*api.Build, int64, error) // ListPendingAndRunningBuilds defines a function that gets a list of pending and running builds. - ListPendingAndRunningBuilds(context.Context, string) ([]*library.BuildQueue, error) + ListPendingAndRunningBuilds(context.Context, string) ([]*api.QueueBuild, error) // ListPendingAndRunningBuildsForRepo defines a function that gets a list of pending and running builds for a repo. - ListPendingAndRunningBuildsForRepo(context.Context, *api.Repo) ([]*library.Build, error) + ListPendingAndRunningBuildsForRepo(context.Context, *api.Repo) ([]*api.Build, error) // UpdateBuild defines a function that updates an existing build. - UpdateBuild(context.Context, *library.Build) (*library.Build, error) + UpdateBuild(context.Context, *api.Build) (*api.Build, error) } diff --git a/database/build/last_repo.go b/database/build/last_repo.go index 3900e62d0..2795d2f47 100644 --- a/database/build/last_repo.go +++ b/database/build/last_repo.go @@ -10,24 +10,25 @@ import ( "gorm.io/gorm" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // LastBuildForRepo gets the last build by repo ID and branch from the database. -func (e *engine) LastBuildForRepo(ctx context.Context, r *api.Repo, branch string) (*library.Build, error) { +func (e *engine) LastBuildForRepo(ctx context.Context, r *api.Repo, branch string) (*api.Build, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), }).Tracef("getting last build for repo %s from the database", r.GetFullName()) // variable to store query results - b := new(database.Build) + b := new(types.Build) // send query to the database and store result in variable err := e.client. Table(constants.TableBuild). + Preload("Repo"). + Preload("Repo.Owner"). Where("repo_id = ?", r.GetID()). Where("branch = ?", branch). Order("number DESC"). @@ -43,5 +44,10 @@ func (e *engine) LastBuildForRepo(ctx context.Context, r *api.Repo, branch strin return nil, err } - return b.ToLibrary(), nil + err = b.Repo.Decrypt(e.config.EncryptionKey) + if err != nil { + e.logger.Errorf("unable to decrypt repo %s/%s: %v", r.GetOrg(), r.GetName(), err) + } + + return b.ToAPI(), nil } diff --git a/database/build/last_repo_test.go b/database/build/last_repo_test.go index 5755d1318..140b79651 100644 --- a/database/build/last_repo_test.go +++ b/database/build/last_repo_test.go @@ -9,26 +9,37 @@ import ( "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" + "github.com/go-vela/types/constants" ) func TestBuild_Engine_LastBuildForRepo(t *testing.T) { // setup types - _build := testBuild() - _build.SetID(1) - _build.SetRepoID(1) - _build.SetNumber(1) - _build.SetDeployPayload(nil) - _build.SetBranch("main") + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) - _repo.GetOwner().SetID(1) + _repo.SetOwner(_owner) _repo.SetHash("baz") _repo.SetOrg("foo") _repo.SetName("bar") _repo.SetFullName("foo/bar") _repo.SetVisibility("public") + _repo.SetAllowEvents(api.NewEventsFromMask(1)) + _repo.SetPipelineType(constants.PipelineTypeYAML) + _repo.SetTopics([]string{}) + + _build := testutils.APIBuild() + _build.SetID(1) + _build.SetRepo(_repo) + _build.SetNumber(1) + _build.SetDeployPayload(nil) + _build.SetBranch("main") _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -38,8 +49,18 @@ func TestBuild_Engine_LastBuildForRepo(t *testing.T) { []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "event_action", "status", "error", "enqueued", "created", "started", "finished", "deploy", "deploy_payload", "clone", "source", "title", "message", "commit", "sender", "author", "email", "link", "branch", "ref", "base_ref", "head_ref", "host", "runtime", "distribution", "approved_at", "approved_by", "timestamp"}). AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "main", "", "", "", "", "", "", 0, "", 0) + _repoRows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows := sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "builds" WHERE repo_id = $1 AND branch = $2 ORDER BY number DESC LIMIT $3`).WithArgs(1, "main", 1).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" = $1`).WithArgs(1).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -49,12 +70,32 @@ func TestBuild_Engine_LastBuildForRepo(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } + err = _sqlite.client.AutoMigrate(&types.Repo{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repo)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&types.User{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + // setup tests tests := []struct { failure bool name string database *engine - want *library.Build + want *api.Build }{ { failure: false, diff --git a/database/build/list.go b/database/build/list.go index 109d2ae5f..2b5176d30 100644 --- a/database/build/list.go +++ b/database/build/list.go @@ -5,19 +5,19 @@ package build import ( "context" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // ListBuilds gets a list of all builds from the database. -func (e *engine) ListBuilds(ctx context.Context) ([]*library.Build, error) { +func (e *engine) ListBuilds(ctx context.Context) ([]*api.Build, error) { e.logger.Trace("listing all builds from the database") // variables to store query results and return value count := int64(0) - b := new([]database.Build) - builds := []*library.Build{} + b := new([]types.Build) + builds := []*api.Build{} // count the results count, err := e.CountBuilds(ctx) @@ -32,6 +32,8 @@ func (e *engine) ListBuilds(ctx context.Context) ([]*library.Build, error) { // send query to the database and store result in variable err = e.client. + Preload("Repo"). + Preload("Repo.Owner"). Table(constants.TableBuild). Find(&b). Error @@ -44,10 +46,12 @@ func (e *engine) ListBuilds(ctx context.Context) ([]*library.Build, error) { // https://golang.org/doc/faq#closures_and_goroutines tmp := build - // convert query result to library type - // - // https://pkg.go.dev/github.com/go-vela/types/database#Build.ToLibrary - builds = append(builds, tmp.ToLibrary()) + err = tmp.Repo.Decrypt(e.config.EncryptionKey) + if err != nil { + e.logger.Errorf("unable to decrypt repo: %v", err) + } + + builds = append(builds, tmp.ToAPI()) } return builds, nil diff --git a/database/build/list_dashboard.go b/database/build/list_dashboard.go index d9f772873..10d2c378d 100644 --- a/database/build/list_dashboard.go +++ b/database/build/list_dashboard.go @@ -8,21 +8,20 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // ListBuildsForDashboardRepo gets a list of builds by repo ID from the database. -func (e *engine) ListBuildsForDashboardRepo(ctx context.Context, r *api.Repo, branches, events []string) ([]*library.Build, error) { +func (e *engine) ListBuildsForDashboardRepo(ctx context.Context, r *api.Repo, branches, events []string) ([]*api.Build, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), }).Tracef("listing builds for repo %s from the database", r.GetFullName()) // variables to store query results and return values - b := new([]database.Build) - builds := []*library.Build{} + b := new([]types.Build) + builds := []*api.Build{} query := e.client.Table(constants.TableBuild).Where("repo_id = ?", r.GetID()) @@ -48,10 +47,7 @@ func (e *engine) ListBuildsForDashboardRepo(ctx context.Context, r *api.Repo, br // https://golang.org/doc/faq#closures_and_goroutines tmp := build - // convert query result to library type - // - // https://pkg.go.dev/github.com/go-vela/types/database#Build.ToLibrary - builds = append(builds, tmp.ToLibrary()) + builds = append(builds, tmp.ToAPI()) } return builds, nil diff --git a/database/build/list_dashboard_test.go b/database/build/list_dashboard_test.go index e73242efb..81a042296 100644 --- a/database/build/list_dashboard_test.go +++ b/database/build/list_dashboard_test.go @@ -9,36 +9,41 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/google/go-cmp/cmp" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_ListBuildsForDashboardRepo(t *testing.T) { // setup types - _buildOne := testBuild() + _repo := testutils.APIRepo() + _repo.SetID(1) + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repo) _buildOne.SetNumber(1) _buildOne.SetDeployPayload(nil) _buildOne.SetCreated(1) _buildOne.SetEvent("push") _buildOne.SetBranch("main") - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repo) _buildTwo.SetNumber(2) _buildTwo.SetDeployPayload(nil) _buildTwo.SetCreated(2) _buildTwo.SetEvent("pull_request") _buildTwo.SetBranch("main") - _repo := testRepo() - _repo.SetID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") + // ListBuildsForDashboardRepo does not return the repo object but the repo ID is needed to create builds + _wantBuildOne := *_buildOne + _wantBuildOne.Repo = testutils.APIRepo() + _wantBuildOne.Repo.Owner = testutils.APIUser().Crop() + + _wantBuildTwo := *_buildTwo + _wantBuildTwo.Repo = testutils.APIRepo() + _wantBuildTwo.Repo.Owner = testutils.APIUser().Crop() _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -70,19 +75,19 @@ func TestBuild_Engine_ListBuildsForDashboardRepo(t *testing.T) { failure bool name string database *engine - want []*library.Build + want []*api.Build }{ { failure: false, name: "postgres", database: _postgres, - want: []*library.Build{_buildTwo, _buildOne}, + want: []*api.Build{&_wantBuildTwo, &_wantBuildOne}, }, { failure: false, name: "sqlite3", database: _sqlite, - want: []*library.Build{_buildTwo, _buildOne}, + want: []*api.Build{&_wantBuildTwo, &_wantBuildOne}, }, } @@ -103,7 +108,7 @@ func TestBuild_Engine_ListBuildsForDashboardRepo(t *testing.T) { t.Errorf("ListBuildsForRepo for %s returned err: %v", test.name, err) } - if diff := cmp.Diff(got, test.want); diff != "" { + if diff := cmp.Diff(test.want, got); diff != "" { t.Errorf("GetDashboard mismatch (-want +got):\n%s", diff) } }) diff --git a/database/build/list_org.go b/database/build/list_org.go index ef7ef140a..0799635b4 100644 --- a/database/build/list_org.go +++ b/database/build/list_org.go @@ -7,23 +7,23 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // ListBuildsForOrg gets a list of builds by org name from the database. // //nolint:lll // ignore long line length due to variable names -func (e *engine) ListBuildsForOrg(ctx context.Context, org string, filters map[string]interface{}, page, perPage int) ([]*library.Build, int64, error) { +func (e *engine) ListBuildsForOrg(ctx context.Context, org string, filters map[string]interface{}, page, perPage int) ([]*api.Build, int64, error) { e.logger.WithFields(logrus.Fields{ "org": org, }).Tracef("listing builds for org %s from the database", org) // variables to store query results and return values count := int64(0) - b := new([]database.Build) - builds := []*library.Build{} + b := new([]types.Build) + builds := []*api.Build{} // count the results count, err := e.CountBuildsForOrg(ctx, org, filters) @@ -41,6 +41,8 @@ func (e *engine) ListBuildsForOrg(ctx context.Context, org string, filters map[s err = e.client. Table(constants.TableBuild). + Preload("Repo"). + Preload("Repo.Owner"). Select("builds.*"). Joins("JOIN repos ON builds.repo_id = repos.id"). Where("repos.org = ?", org). @@ -60,10 +62,12 @@ func (e *engine) ListBuildsForOrg(ctx context.Context, org string, filters map[s // https://golang.org/doc/faq#closures_and_goroutines tmp := build - // convert query result to library type - // - // https://pkg.go.dev/github.com/go-vela/types/database#Build.ToLibrary - builds = append(builds, tmp.ToLibrary()) + err = tmp.Repo.Decrypt(e.config.EncryptionKey) + if err != nil { + e.logger.Errorf("unable to decrypt repo: %v", err) + } + + builds = append(builds, tmp.ToAPI()) } return builds, count, nil diff --git a/database/build/list_org_test.go b/database/build/list_org_test.go index 488cf1e33..4d25d6062 100644 --- a/database/build/list_org_test.go +++ b/database/build/list_org_test.go @@ -4,54 +4,62 @@ package build import ( "context" - "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" + "github.com/google/go-cmp/cmp" - "github.com/go-vela/server/database/repo" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { // setup types - _buildOne := testBuild() - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetDeployPayload(nil) - _buildOne.SetEvent("push") - - _buildTwo := testBuild() - _buildTwo.SetID(2) - _buildTwo.SetRepoID(2) - _buildTwo.SetNumber(2) - _buildTwo.SetDeployPayload(nil) - _buildTwo.SetEvent("push") + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") - _repoOne := testRepo() + _repoOne := testutils.APIRepo() _repoOne.SetID(1) - _repoOne.GetOwner().SetID(1) + _repoOne.SetOwner(_owner) _repoOne.SetHash("baz") _repoOne.SetOrg("foo") _repoOne.SetName("bar") _repoOne.SetFullName("foo/bar") _repoOne.SetVisibility("public") _repoOne.SetPipelineType("yaml") + _repoOne.SetAllowEvents(api.NewEventsFromMask(1)) _repoOne.SetTopics([]string{}) - _repoTwo := testRepo() + _repoTwo := testutils.APIRepo() _repoTwo.SetID(2) - _repoTwo.GetOwner().SetID(1) + _repoTwo.SetOwner(_owner) _repoTwo.SetHash("bar") _repoTwo.SetOrg("foo") _repoTwo.SetName("baz") _repoTwo.SetFullName("foo/baz") _repoTwo.SetVisibility("public") _repoTwo.SetPipelineType("yaml") + _repoTwo.SetAllowEvents(api.NewEventsFromMask(1)) _repoTwo.SetTopics([]string{}) + _buildOne := testutils.APIBuild() + _buildOne.SetID(1) + _buildOne.SetRepo(_repoOne) + _buildOne.SetNumber(1) + _buildOne.SetDeployPayload(nil) + _buildOne.SetEvent("push") + + _buildTwo := testutils.APIBuild() + _buildTwo.SetID(2) + _buildTwo.SetRepo(_repoTwo) + _buildTwo.SetNumber(2) + _buildTwo.SetDeployPayload(nil) + _buildTwo.SetEvent("push") + _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -64,8 +72,20 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "event_action", "status", "error", "enqueued", "created", "started", "finished", "deploy", "deploy_payload", "clone", "source", "title", "message", "commit", "sender", "author", "email", "link", "branch", "ref", "base_ref", "head_ref", "host", "runtime", "distribution", "approved_at", "approved_by", "timestamp"}). AddRow(1, 1, nil, 1, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0). AddRow(2, 2, nil, 2, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0) + + _repoRows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", ""). + AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows := sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the query without filters _mock.ExpectQuery(`SELECT builds.* FROM "builds" JOIN repos ON builds.repo_id = repos.id WHERE repos.org = $1 ORDER BY created DESC,id LIMIT $2`).WithArgs("foo", 10).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" IN ($1,$2)`).WithArgs(1, 2).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) // create expected count query with event filter result in mock _rows = sqlmock.NewRows([]string{"count"}).AddRow(2) @@ -76,8 +96,20 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "event_action", "status", "error", "enqueued", "created", "started", "finished", "deploy", "deploy_payload", "clone", "source", "title", "message", "commit", "sender", "author", "email", "link", "branch", "ref", "base_ref", "head_ref", "host", "runtime", "distribution", "approved_at", "approved_by", "timestamp"}). AddRow(1, 1, nil, 1, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0). AddRow(2, 2, nil, 2, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0) + + _repoRows = sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", ""). + AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows = sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the query with event filter _mock.ExpectQuery(`SELECT builds.* FROM "builds" JOIN repos ON builds.repo_id = repos.id WHERE repos.org = $1 AND "event" = $2 ORDER BY created DESC,id LIMIT $3`).WithArgs("foo", "push", 10).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" IN ($1,$2)`).WithArgs(1, 2).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) // create expected count query with visibility filter result in mock _rows = sqlmock.NewRows([]string{"count"}).AddRow(2) @@ -88,8 +120,20 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { []string{"id", "repo_id", "pipeline_id", "number", "parent", "event", "event_action", "status", "error", "enqueued", "created", "started", "finished", "deploy", "deploy_payload", "clone", "source", "title", "message", "commit", "sender", "author", "email", "link", "branch", "ref", "base_ref", "head_ref", "host", "runtime", "distribution", "approved_at", "approved_by", "timestamp"}). AddRow(1, 1, nil, 1, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0). AddRow(2, 2, nil, 2, 0, "push", "", "", "", 0, 0, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0) + + _repoRows = sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", ""). + AddRow(2, 1, "bar", "foo", "baz", "foo/baz", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows = sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the query with visibility filter _mock.ExpectQuery(`SELECT builds.* FROM "builds" JOIN repos ON builds.repo_id = repos.id WHERE repos.org = $1 AND "visibility" = $2 ORDER BY created DESC,id LIMIT $3`).WithArgs("foo", "public", 10).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" IN ($1,$2)`).WithArgs(1, 2).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -104,35 +148,45 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&repo.Repo{}) + err = _sqlite.client.AutoMigrate(&types.Repo{}) if err != nil { t.Errorf("unable to create repo table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableRepo).Create(repo.FromAPI(_repoOne)).Error + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repoOne)).Error if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableRepo).Create(repo.FromAPI(_repoTwo)).Error + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repoTwo)).Error if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } + err = _sqlite.client.AutoMigrate(&types.User{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + // setup tests tests := []struct { failure bool name string database *engine filters map[string]interface{} - want []*library.Build + want []*api.Build }{ { failure: false, name: "postgres without filters", database: _postgres, filters: map[string]interface{}{}, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, { failure: false, @@ -141,7 +195,7 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { filters: map[string]interface{}{ "event": "push", }, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, { failure: false, @@ -150,14 +204,14 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { filters: map[string]interface{}{ "visibility": "public", }, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, { failure: false, name: "sqlite3 without filters", database: _sqlite, filters: map[string]interface{}{}, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, { failure: false, @@ -166,7 +220,7 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { filters: map[string]interface{}{ "event": "push", }, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, { failure: false, @@ -175,7 +229,7 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { filters: map[string]interface{}{ "visibility": "public", }, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, } @@ -196,8 +250,8 @@ func TestBuild_Engine_ListBuildsForOrg(t *testing.T) { t.Errorf("ListBuildsForOrg for %s returned err: %v", test.name, err) } - if !reflect.DeepEqual(got, test.want) { - t.Errorf("ListBuildsForOrg for %s is %v, want %v", test.name, got, test.want) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("ListBuildsForOrg for %s mismatch (-want +got):\n%s", test.name, diff) } }) } diff --git a/database/build/list_pending_running.go b/database/build/list_pending_running.go index de4b4ac68..ae40ece51 100644 --- a/database/build/list_pending_running.go +++ b/database/build/list_pending_running.go @@ -5,18 +5,18 @@ package build import ( "context" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // ListPendingAndRunningBuilds gets a list of all pending and running builds in the provided timeframe from the database. -func (e *engine) ListPendingAndRunningBuilds(ctx context.Context, after string) ([]*library.BuildQueue, error) { +func (e *engine) ListPendingAndRunningBuilds(ctx context.Context, after string) ([]*api.QueueBuild, error) { e.logger.Trace("listing all pending and running builds from the database") // variables to store query results and return value - b := new([]database.BuildQueue) - builds := []*library.BuildQueue{} + b := new([]types.QueueBuild) + builds := []*api.QueueBuild{} // send query to the database and store result in variable err := e.client. @@ -36,10 +36,7 @@ func (e *engine) ListPendingAndRunningBuilds(ctx context.Context, after string) // https://golang.org/doc/faq#closures_and_goroutines tmp := build - // convert query result to library type - // - // https://pkg.go.dev/github.com/go-vela/types/database#Build.ToLibrary - builds = append(builds, tmp.ToLibrary()) + builds = append(builds, tmp.ToAPI()) } return builds, nil diff --git a/database/build/list_pending_running_repo.go b/database/build/list_pending_running_repo.go index 119b78625..6213bab29 100644 --- a/database/build/list_pending_running_repo.go +++ b/database/build/list_pending_running_repo.go @@ -6,22 +6,23 @@ import ( "context" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // ListPendingAndRunningBuilds gets a list of all pending and running builds in the provided timeframe from the database. -func (e *engine) ListPendingAndRunningBuildsForRepo(ctx context.Context, repo *api.Repo) ([]*library.Build, error) { +func (e *engine) ListPendingAndRunningBuildsForRepo(ctx context.Context, repo *api.Repo) ([]*api.Build, error) { e.logger.Trace("listing all pending and running builds from the database") // variables to store query results and return value - b := new([]database.Build) - builds := []*library.Build{} + b := new([]types.Build) + builds := []*api.Build{} // send query to the database and store result in variable err := e.client. Table(constants.TableBuild). + Preload("Repo"). + Preload("Repo.Owner"). Select("*"). Where("repo_id = ?", repo.GetID()). Where("status = 'running' OR status = 'pending' OR status = 'pending approval'"). @@ -36,10 +37,12 @@ func (e *engine) ListPendingAndRunningBuildsForRepo(ctx context.Context, repo *a // https://golang.org/doc/faq#closures_and_goroutines tmp := build - // convert query result to library type - // - // https://pkg.go.dev/github.com/go-vela/types/database#Build.ToLibrary - builds = append(builds, tmp.ToLibrary()) + err = tmp.Repo.Decrypt(e.config.EncryptionKey) + if err != nil { + e.logger.Errorf("unable to decrypt repo %s/%s: %v", repo.GetOrg(), repo.GetName(), err) + } + + builds = append(builds, tmp.ToAPI()) } return builds, nil diff --git a/database/build/list_pending_running_repo_test.go b/database/build/list_pending_running_repo_test.go index 8ea610fb6..286b68141 100644 --- a/database/build/list_pending_running_repo_test.go +++ b/database/build/list_pending_running_repo_test.go @@ -4,60 +4,72 @@ package build import ( "context" - "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" + "github.com/google/go-cmp/cmp" - "github.com/go-vela/server/database/repo" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) func TestBuild_Engine_ListPendingAndRunningBuildsForRepo(t *testing.T) { // setup types - _buildOne := testBuild() + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repoOne := testutils.APIRepo() + _repoOne.SetID(1) + _repoOne.SetOwner(_owner) + _repoOne.SetHash("baz") + _repoOne.SetOrg("foo") + _repoOne.SetName("bar") + _repoOne.SetFullName("foo/bar") + _repoOne.SetVisibility("public") + _repoOne.SetPipelineType("yaml") + _repoOne.SetAllowEvents(api.NewEventsFromMask(1)) + _repoOne.SetTopics([]string{}) + + _repoTwo := testutils.APIRepo() + _repoTwo.SetID(2) + _repoTwo.SetOwner(_owner) + _repoTwo.SetHash("bar") + _repoTwo.SetOrg("foo") + _repoTwo.SetName("baz") + _repoTwo.SetFullName("foo/baz") + _repoTwo.SetVisibility("public") + _repoTwo.SetPipelineType("yaml") + _repoTwo.SetAllowEvents(api.NewEventsFromMask(1)) + _repoTwo.SetTopics([]string{}) + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repoOne) _buildOne.SetNumber(1) _buildOne.SetStatus("running") _buildOne.SetCreated(1) _buildOne.SetDeployPayload(nil) - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repoOne) _buildTwo.SetNumber(2) _buildTwo.SetStatus("pending") _buildTwo.SetCreated(1) _buildTwo.SetDeployPayload(nil) - _buildThree := testBuild() + _buildThree := testutils.APIBuild() _buildThree.SetID(3) - _buildThree.SetRepoID(2) + _buildThree.SetRepo(_repoTwo) _buildThree.SetNumber(1) _buildThree.SetStatus("pending") _buildThree.SetCreated(1) _buildThree.SetDeployPayload(nil) - _repo := testRepo() - _repo.SetID(1) - _repo.GetOwner().SetID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - - _repoTwo := testRepo() - _repoTwo.SetID(2) - _repoTwo.GetOwner().SetID(1) - _repoTwo.SetHash("bazzy") - _repoTwo.SetOrg("foo") - _repoTwo.SetName("baz") - _repoTwo.SetFullName("foo/baz") - _repoTwo.SetVisibility("public") - _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -67,8 +79,18 @@ func TestBuild_Engine_ListPendingAndRunningBuildsForRepo(t *testing.T) { AddRow(2, 1, nil, 2, 0, "", "", "pending", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0). AddRow(1, 1, nil, 1, 0, "", "", "running", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0) + _repoRows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows := sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the name query _mock.ExpectQuery(`SELECT * FROM "builds" WHERE repo_id = $1 AND (status = 'running' OR status = 'pending' OR status = 'pending approval')`).WithArgs(1).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" = $1`).WithArgs(1).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -88,46 +110,56 @@ func TestBuild_Engine_ListPendingAndRunningBuildsForRepo(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&repo.Repo{}) + err = _sqlite.client.AutoMigrate(&types.Repo{}) if err != nil { t.Errorf("unable to create repo table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableRepo).Create(repo.FromAPI(_repo)).Error + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repoOne)).Error if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableRepo).Create(repo.FromAPI(_repoTwo)).Error + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repoTwo)).Error if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } + err = _sqlite.client.AutoMigrate(&types.User{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + // setup tests tests := []struct { failure bool name string database *engine - want []*library.Build + want []*api.Build }{ { failure: false, name: "postgres", database: _postgres, - want: []*library.Build{_buildTwo, _buildOne}, + want: []*api.Build{_buildTwo, _buildOne}, }, { failure: false, name: "sqlite3", database: _sqlite, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, } // run tests for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := test.database.ListPendingAndRunningBuildsForRepo(context.TODO(), _repo) + got, err := test.database.ListPendingAndRunningBuildsForRepo(context.TODO(), _repoOne) if test.failure { if err == nil { @@ -141,8 +173,8 @@ func TestBuild_Engine_ListPendingAndRunningBuildsForRepo(t *testing.T) { t.Errorf("ListPendingAndRunningBuildsForRepo for %s returned err: %v", test.name, err) } - if !reflect.DeepEqual(got, test.want) { - t.Errorf("ListPendingAndRunningBuildsForRepo for %s is %v, want %v", test.name, got, test.want) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("ListPendingAndRunningBuildsForRepo for %s mismatch (-want +got):\n%s", test.name, diff) } }) } diff --git a/database/build/list_pending_running_test.go b/database/build/list_pending_running_test.go index 5b427702f..c164827d8 100644 --- a/database/build/list_pending_running_test.go +++ b/database/build/list_pending_running_test.go @@ -9,50 +9,56 @@ import ( "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/server/database/repo" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) func TestBuild_Engine_ListPendingAndRunningBuilds(t *testing.T) { // setup types - _buildOne := testBuild() + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.SetOwner(_owner) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repo) _buildOne.SetNumber(1) _buildOne.SetStatus("running") _buildOne.SetCreated(1) _buildOne.SetDeployPayload(nil) - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repo) _buildTwo.SetNumber(2) _buildTwo.SetStatus("pending") _buildTwo.SetCreated(1) _buildTwo.SetDeployPayload(nil) - _queueOne := new(library.BuildQueue) + _queueOne := new(api.QueueBuild) _queueOne.SetCreated(1) _queueOne.SetFullName("foo/bar") _queueOne.SetNumber(1) _queueOne.SetStatus("running") - _queueTwo := new(library.BuildQueue) + _queueTwo := new(api.QueueBuild) _queueTwo.SetCreated(1) _queueTwo.SetFullName("foo/bar") _queueTwo.SetNumber(2) _queueTwo.SetStatus("pending") - _repo := testRepo() - _repo.SetID(1) - _repo.GetOwner().SetID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -75,12 +81,12 @@ func TestBuild_Engine_ListPendingAndRunningBuilds(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&repo.Repo{}) + err = _sqlite.client.AutoMigrate(&types.Repo{}) if err != nil { t.Errorf("unable to create repo table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableRepo).Create(repo.FromAPI(_repo)).Error + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repo)).Error if err != nil { t.Errorf("unable to create test repo for sqlite: %v", err) } @@ -90,19 +96,19 @@ func TestBuild_Engine_ListPendingAndRunningBuilds(t *testing.T) { failure bool name string database *engine - want []*library.BuildQueue + want []*api.QueueBuild }{ { failure: false, name: "postgres", database: _postgres, - want: []*library.BuildQueue{_queueTwo, _queueOne}, + want: []*api.QueueBuild{_queueTwo, _queueOne}, }, { failure: false, name: "sqlite3", database: _sqlite, - want: []*library.BuildQueue{_queueTwo, _queueOne}, + want: []*api.QueueBuild{_queueTwo, _queueOne}, }, } diff --git a/database/build/list_repo.go b/database/build/list_repo.go index 87f8c3389..753c941c2 100644 --- a/database/build/list_repo.go +++ b/database/build/list_repo.go @@ -8,15 +8,14 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // ListBuildsForRepo gets a list of builds by repo ID from the database. // //nolint:lll // ignore long line length due to variable names -func (e *engine) ListBuildsForRepo(ctx context.Context, r *api.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*library.Build, int64, error) { +func (e *engine) ListBuildsForRepo(ctx context.Context, r *api.Repo, filters map[string]interface{}, before, after int64, page, perPage int) ([]*api.Build, int64, error) { e.logger.WithFields(logrus.Fields{ "org": r.GetOrg(), "repo": r.GetName(), @@ -24,8 +23,8 @@ func (e *engine) ListBuildsForRepo(ctx context.Context, r *api.Repo, filters map // variables to store query results and return values count := int64(0) - b := new([]database.Build) - builds := []*library.Build{} + b := new([]types.Build) + builds := []*api.Build{} // count the results count, err := e.CountBuildsForRepo(ctx, r, filters) @@ -43,6 +42,8 @@ func (e *engine) ListBuildsForRepo(ctx context.Context, r *api.Repo, filters map err = e.client. Table(constants.TableBuild). + Preload("Repo"). + Preload("Repo.Owner"). Where("repo_id = ?", r.GetID()). Where("created < ?", before). Where("created > ?", after). @@ -61,10 +62,12 @@ func (e *engine) ListBuildsForRepo(ctx context.Context, r *api.Repo, filters map // https://golang.org/doc/faq#closures_and_goroutines tmp := build - // convert query result to library type - // - // https://pkg.go.dev/github.com/go-vela/types/database#Build.ToLibrary - builds = append(builds, tmp.ToLibrary()) + err = tmp.Repo.Decrypt(e.config.EncryptionKey) + if err != nil { + e.logger.Errorf("unable to decrypt repo %s/%s: %v", r.GetOrg(), r.GetName(), err) + } + + builds = append(builds, tmp.ToAPI()) } return builds, count, nil diff --git a/database/build/list_repo_test.go b/database/build/list_repo_test.go index 1f0e0fb9d..96368faec 100644 --- a/database/build/list_repo_test.go +++ b/database/build/list_repo_test.go @@ -10,34 +10,45 @@ import ( "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" + "github.com/go-vela/types/constants" ) func TestBuild_Engine_ListBuildsForRepo(t *testing.T) { // setup types - _buildOne := testBuild() + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.SetOwner(_owner) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetAllowEvents(api.NewEventsFromMask(1)) + _repo.SetPipelineType(constants.PipelineTypeYAML) + _repo.SetTopics([]string{}) + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repo) _buildOne.SetNumber(1) _buildOne.SetDeployPayload(nil) _buildOne.SetCreated(1) - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repo) _buildTwo.SetNumber(2) _buildTwo.SetDeployPayload(nil) _buildTwo.SetCreated(2) - _repo := testRepo() - _repo.SetID(1) - _repo.GetOwner().SetID(1) - _repo.SetHash("baz") - _repo.SetOrg("foo") - _repo.SetName("bar") - _repo.SetFullName("foo/bar") - _repo.SetVisibility("public") - _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -53,8 +64,18 @@ func TestBuild_Engine_ListBuildsForRepo(t *testing.T) { AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 2, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0). AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 1, 0, 0, "", nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0, "", 0) + _repoRows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows := sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "builds" WHERE repo_id = $1 AND created < $2 AND created > $3 ORDER BY number DESC LIMIT $4`).WithArgs(1, AnyArgument{}, 0, 10).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" = $1`).WithArgs(1).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -69,24 +90,44 @@ func TestBuild_Engine_ListBuildsForRepo(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } + err = _sqlite.client.AutoMigrate(&types.Repo{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repo)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&types.User{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + // setup tests tests := []struct { failure bool name string database *engine - want []*library.Build + want []*api.Build }{ { failure: false, name: "postgres", database: _postgres, - want: []*library.Build{_buildTwo, _buildOne}, + want: []*api.Build{_buildTwo, _buildOne}, }, { failure: false, name: "sqlite3", database: _sqlite, - want: []*library.Build{_buildTwo, _buildOne}, + want: []*api.Build{_buildTwo, _buildOne}, }, } diff --git a/database/build/list_test.go b/database/build/list_test.go index ec645ace1..15688d252 100644 --- a/database/build/list_test.go +++ b/database/build/list_test.go @@ -9,21 +9,41 @@ import ( "github.com/DATA-DOG/go-sqlmock" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" + "github.com/go-vela/types/constants" ) func TestBuild_Engine_ListBuilds(t *testing.T) { // setup types - _buildOne := testBuild() + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.SetOwner(_owner) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetAllowEvents(api.NewEventsFromMask(1)) + _repo.SetPipelineType(constants.PipelineTypeYAML) + _repo.SetTopics([]string{}) + + _buildOne := testutils.APIBuild() _buildOne.SetID(1) - _buildOne.SetRepoID(1) + _buildOne.SetRepo(_repo) _buildOne.SetNumber(1) _buildOne.SetDeployNumber(0) _buildOne.SetDeployPayload(nil) - _buildTwo := testBuild() + _buildTwo := testutils.APIBuild() _buildTwo.SetID(2) - _buildTwo.SetRepoID(1) + _buildTwo.SetRepo(_repo) _buildTwo.SetNumber(2) _buildTwo.SetDeployNumber(0) _buildTwo.SetDeployPayload(nil) @@ -43,8 +63,18 @@ func TestBuild_Engine_ListBuilds(t *testing.T) { AddRow(1, 1, nil, 1, 0, "", "", "", "", 0, 0, 0, 0, "", 0, nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0). AddRow(2, 1, nil, 2, 0, "", "", "", "", 0, 0, 0, 0, "", 0, nil, "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 0) + _repoRows := sqlmock.NewRows( + []string{"id", "user_id", "hash", "org", "name", "full_name", "link", "clone", "branch", "topics", "build_limit", "timeout", "counter", "visibility", "private", "trusted", "active", "allow_events", "pipeline_type", "previous_name", "approve_build"}). + AddRow(1, 1, "baz", "foo", "bar", "foo/bar", "", "", "", "{}", 0, 0, 0, "public", false, false, false, 1, "yaml", "", "") + + _userRows := sqlmock.NewRows( + []string{"id", "name", "token", "hash", "active", "admin"}). + AddRow(1, "foo", "bar", "baz", false, false) + // ensure the mock expects the query _mock.ExpectQuery(`SELECT * FROM "builds"`).WillReturnRows(_rows) + _mock.ExpectQuery(`SELECT * FROM "repos" WHERE "repos"."id" = $1`).WithArgs(1).WillReturnRows(_repoRows) + _mock.ExpectQuery(`SELECT * FROM "users" WHERE "users"."id" = $1`).WithArgs(1).WillReturnRows(_userRows) _sqlite := testSqlite(t) defer func() { _sql, _ := _sqlite.client.DB(); _sql.Close() }() @@ -59,24 +89,44 @@ func TestBuild_Engine_ListBuilds(t *testing.T) { t.Errorf("unable to create test build for sqlite: %v", err) } + err = _sqlite.client.AutoMigrate(&types.Repo{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableRepo).Create(types.RepoFromAPI(_repo)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + + err = _sqlite.client.AutoMigrate(&types.User{}) + if err != nil { + t.Errorf("unable to create build table for sqlite: %v", err) + } + + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error + if err != nil { + t.Errorf("unable to create test user for sqlite: %v", err) + } + // setup tests tests := []struct { failure bool name string database *engine - want []*library.Build + want []*api.Build }{ { failure: false, name: "postgres", database: _postgres, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, { failure: false, name: "sqlite3", database: _sqlite, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, } diff --git a/database/build/opts.go b/database/build/opts.go index b3a68e3c7..0c3a661be 100644 --- a/database/build/opts.go +++ b/database/build/opts.go @@ -22,6 +22,16 @@ func WithClient(client *gorm.DB) EngineOpt { } } +// WithEncryptionKey sets the encryption key in the database engine for Repos. +func WithEncryptionKey(key string) EngineOpt { + return func(e *engine) error { + // set the encryption key in the repo engine + e.config.EncryptionKey = key + + return nil + } +} + // WithLogger sets the github.com/sirupsen/logrus logger in the database engine for Builds. func WithLogger(logger *logrus.Entry) EngineOpt { return func(e *engine) error { diff --git a/database/build/update.go b/database/build/update.go index ff5519fc9..0657470aa 100644 --- a/database/build/update.go +++ b/database/build/update.go @@ -8,25 +8,19 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) // UpdateBuild updates an existing build in the database. -func (e *engine) UpdateBuild(ctx context.Context, b *library.Build) (*library.Build, error) { +func (e *engine) UpdateBuild(ctx context.Context, b *api.Build) (*api.Build, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("updating build %d in the database", b.GetNumber()) - // cast the library type to database type - // - // https://pkg.go.dev/github.com/go-vela/types/database#BuildFromLibrary - build := database.BuildFromLibrary(b) + build := types.BuildFromAPI(b) - // validate the necessary fields are populated - // - // https://pkg.go.dev/github.com/go-vela/types/database#Build.Validate err := build.Validate() if err != nil { return nil, err @@ -36,7 +30,13 @@ func (e *engine) UpdateBuild(ctx context.Context, b *library.Build) (*library.Bu build = build.Crop() // send query to the database - result := e.client.Table(constants.TableBuild).Save(build) + err = e.client.Table(constants.TableBuild).Save(build).Error + if err != nil { + return nil, err + } + + result := build.ToAPI() + result.SetRepo(b.GetRepo()) - return build.ToLibrary(), result.Error + return result, nil } diff --git a/database/build/update_test.go b/database/build/update_test.go index 4d75183df..149779780 100644 --- a/database/build/update_test.go +++ b/database/build/update_test.go @@ -8,13 +8,31 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestBuild_Engine_UpdateBuild(t *testing.T) { // setup types - _build := testBuild() + _owner := testutils.APIUser() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repo := testutils.APIRepo() + _repo.SetID(1) + _repo.SetOwner(_owner) + _repo.SetHash("baz") + _repo.SetOrg("foo") + _repo.SetName("bar") + _repo.SetFullName("foo/bar") + _repo.SetVisibility("public") + _repo.SetAllowEvents(api.NewEventsFromMask(1)) + + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(_repo) _build.SetNumber(1) _build.SetDeployPayload(nil) diff --git a/database/dashboard/create.go b/database/dashboard/create.go index 5e7ec7887..5d179e11e 100644 --- a/database/dashboard/create.go +++ b/database/dashboard/create.go @@ -9,6 +9,7 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/constants" + "github.com/go-vela/server/database/types" ) // CreateDashboard creates a new dashboard in the database. @@ -17,7 +18,7 @@ func (e *engine) CreateDashboard(ctx context.Context, d *api.Dashboard) (*api.Da "dashboard": d.GetName(), }).Tracef("creating dashboard %s in the database", d.GetName()) - dashboard := FromAPI(d) + dashboard := types.DashboardFromAPI(d) err := dashboard.Validate() if err != nil { diff --git a/database/dashboard/create_test.go b/database/dashboard/create_test.go index 041a39149..dba9fffc3 100644 --- a/database/dashboard/create_test.go +++ b/database/dashboard/create_test.go @@ -10,6 +10,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestDashboard_Engine_CreateDashboard(t *testing.T) { @@ -26,7 +27,7 @@ func TestDashboard_Engine_CreateDashboard(t *testing.T) { _admin.SetActive(true) _admins := []*api.User{_admin} - _dashboard := testDashboard() + _dashboard := testutils.APIDashboard() _dashboard.SetID("c8da1302-07d6-11ea-882f-4893bca275b8") _dashboard.SetName("dash") _dashboard.SetCreatedAt(1) diff --git a/database/dashboard/dashboard.go b/database/dashboard/dashboard.go index 321cfe609..8cd70c080 100644 --- a/database/dashboard/dashboard.go +++ b/database/dashboard/dashboard.go @@ -4,19 +4,13 @@ package dashboard import ( "context" - "database/sql" - "database/sql/driver" - "encoding/json" "errors" "fmt" - "github.com/google/uuid" "github.com/sirupsen/logrus" "gorm.io/gorm" - api "github.com/go-vela/server/api/types" "github.com/go-vela/server/constants" - "github.com/go-vela/server/util" ) var ( @@ -55,21 +49,6 @@ type ( // https://pkg.go.dev/github.com/sirupsen/logrus#Entry logger *logrus.Entry } - - // Dashboard is the database representation of a dashboard. - Dashboard struct { - ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4()"` - Name sql.NullString `sql:"name"` - CreatedAt sql.NullInt64 `sql:"created_at"` - CreatedBy sql.NullString `sql:"created_by"` - UpdatedAt sql.NullInt64 `sql:"updated_at"` - UpdatedBy sql.NullString `sql:"updated_by"` - Admins AdminsJSON - Repos DashReposJSON - } - - DashReposJSON []*api.DashboardRepo - AdminsJSON []*api.User ) // New creates and returns a Vela service for integrating with dashboards in the database. @@ -107,142 +86,3 @@ func New(opts ...EngineOpt) (*engine, error) { return e, nil } - -// Value - Implementation of valuer for database/sql for DashReposJSON. -func (r DashReposJSON) Value() (driver.Value, error) { - valueString, err := json.Marshal(r) - return string(valueString), err -} - -// Scan - Implement the database/sql scanner interface for DashReposJSON. -func (r *DashReposJSON) Scan(value interface{}) error { - switch v := value.(type) { - case []byte: - return json.Unmarshal(v, &r) - case string: - return json.Unmarshal([]byte(v), &r) - default: - return fmt.Errorf("wrong type for repos: %T", v) - } -} - -// Value - Implementation of valuer for database/sql for AdminsJSON. -func (a AdminsJSON) Value() (driver.Value, error) { - valueString, err := json.Marshal(a) - return string(valueString), err -} - -// Scan - Implement the database/sql scanner interface for AdminsJSON. -func (a *AdminsJSON) Scan(value interface{}) error { - switch v := value.(type) { - case []byte: - return json.Unmarshal(v, &a) - case string: - return json.Unmarshal([]byte(v), &a) - default: - return fmt.Errorf("wrong type for admins: %T", v) - } -} - -// Nullify ensures the valid flag for -// the sql.Null types are properly set. -// -// When a field within the Dashboard type is the zero -// value for the field, the valid flag is set to -// false causing it to be NULL in the database. -func (d *Dashboard) Nullify() *Dashboard { - if d == nil { - return nil - } - - // check if the Name field should be false - if len(d.Name.String) == 0 { - d.Name.Valid = false - } - - // check if the CreatedAt field should be false - if d.CreatedAt.Int64 == 0 { - d.CreatedAt.Valid = false - } - - // check if the CreatedBy field should be false - if len(d.CreatedBy.String) == 0 { - d.CreatedBy.Valid = false - } - - // check if the UpdatedAt field should be false - if d.UpdatedAt.Int64 == 0 { - d.UpdatedAt.Valid = false - } - - // check if the UpdatedBy field should be false - if len(d.UpdatedBy.String) == 0 { - d.UpdatedBy.Valid = false - } - - return d -} - -// ToAPI converts the Dashboard type -// to an API Dashboard type. -func (d *Dashboard) ToAPI() *api.Dashboard { - dashboard := new(api.Dashboard) - - dashboard.SetID(d.ID.String()) - dashboard.SetName(d.Name.String) - dashboard.SetAdmins(d.Admins) - dashboard.SetCreatedAt(d.CreatedAt.Int64) - dashboard.SetCreatedBy(d.CreatedBy.String) - dashboard.SetUpdatedAt(d.UpdatedAt.Int64) - dashboard.SetUpdatedBy(d.UpdatedBy.String) - dashboard.SetRepos(d.Repos) - - return dashboard -} - -// Validate verifies the necessary fields for -// the Dashboard type are populated correctly. -func (d *Dashboard) Validate() error { - // verify the Name field is populated - if len(d.Name.String) == 0 { - return ErrEmptyDashName - } - - // ensure that all Dashboard string fields - // that can be returned as JSON are sanitized - // to avoid unsafe HTML content - d.Name = sql.NullString{String: util.Sanitize(d.Name.String), Valid: d.Name.Valid} - - return nil -} - -// FromAPI converts the API Dashboard type -// to a database Dashboard type. -func FromAPI(d *api.Dashboard) *Dashboard { - var ( - id uuid.UUID - err error - ) - - if d.GetID() == "" { - id = uuid.New() - } else { - id, err = uuid.Parse(d.GetID()) - if err != nil { - return nil - } - } - - dashboard := &Dashboard{ - ID: id, - Name: sql.NullString{String: d.GetName(), Valid: true}, - CreatedAt: sql.NullInt64{Int64: d.GetCreatedAt(), Valid: true}, - CreatedBy: sql.NullString{String: d.GetCreatedBy(), Valid: true}, - UpdatedAt: sql.NullInt64{Int64: d.GetUpdatedAt(), Valid: true}, - UpdatedBy: sql.NullString{String: d.GetUpdatedBy(), Valid: true}, - Admins: d.GetAdmins(), - Repos: d.GetRepos(), - } - - return dashboard.Nullify() -} diff --git a/database/dashboard/dashboard_test.go b/database/dashboard/dashboard_test.go index 3073fe299..77d5069a9 100644 --- a/database/dashboard/dashboard_test.go +++ b/database/dashboard/dashboard_test.go @@ -13,8 +13,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - api "github.com/go-vela/server/api/types" ) func TestDashboard_New(t *testing.T) { @@ -166,40 +164,6 @@ func testSqlite(t *testing.T) *engine { return _engine } -// testAdmin is a test helper function to create an API -// User type wil all fields set to their zero values. -func testAdmins() *[]*api.User { - return &[]*api.User{ - { - ID: new(int64), - Name: new(string), - Active: new(bool), - }, - } -} - -// testDashboard is a test helper function to create a library -// Dashboard type with all fields set to their zero values. -func testDashboard() *api.Dashboard { - return &api.Dashboard{ - ID: new(string), - Name: new(string), - CreatedAt: new(int64), - CreatedBy: new(string), - UpdatedAt: new(int64), - UpdatedBy: new(string), - Admins: testAdmins(), - } -} - -func testDashboardRepo() *api.DashboardRepo { - return &api.DashboardRepo{ - ID: new(int64), - Branches: new([]string), - Events: new([]string), - } -} - // This will be used with the github.com/DATA-DOG/go-sqlmock library to compare values // that are otherwise not easily compared. These typically would be values generated // before adding or updating them in the database. diff --git a/database/dashboard/delete.go b/database/dashboard/delete.go index b2b1e4090..c0bf658ee 100644 --- a/database/dashboard/delete.go +++ b/database/dashboard/delete.go @@ -9,6 +9,7 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/constants" + "github.com/go-vela/server/database/types" ) // DeleteDashboard deletes an existing dashboard from the database. @@ -17,7 +18,7 @@ func (e *engine) DeleteDashboard(ctx context.Context, d *api.Dashboard) error { "dashboard": d.GetID(), }).Tracef("deleting dashboard %s from the database", d.GetID()) - dashboard := FromAPI(d) + dashboard := types.DashboardFromAPI(d) // send query to the database return e.client. diff --git a/database/dashboard/delete_test.go b/database/dashboard/delete_test.go index 3c079efd1..1987d51a4 100644 --- a/database/dashboard/delete_test.go +++ b/database/dashboard/delete_test.go @@ -9,18 +9,19 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestDashboard_Engine_DeleteDashboard(t *testing.T) { // setup types - _dashboard := testDashboard() + _dashboard := testutils.APIDashboard() _dashboard.SetID("c8da1302-07d6-11ea-882f-4893bca275b8") _dashboard.SetName("vela") _dashboard.SetCreatedAt(1) _dashboard.SetCreatedBy("user1") _dashboard.SetUpdatedAt(1) _dashboard.SetUpdatedBy("user2") - _dashboard.SetRepos([]*api.DashboardRepo{testDashboardRepo()}) + _dashboard.SetRepos([]*api.DashboardRepo{testutils.APIDashboardRepo()}) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() diff --git a/database/dashboard/get.go b/database/dashboard/get.go index e4b9694b9..1e08391f9 100644 --- a/database/dashboard/get.go +++ b/database/dashboard/get.go @@ -7,6 +7,7 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/constants" + "github.com/go-vela/server/database/types" ) // GetDashboard gets a dashboard by UUID from the database. @@ -14,17 +15,17 @@ func (e *engine) GetDashboard(ctx context.Context, id string) (*api.Dashboard, e e.logger.Tracef("getting dashboard %s from the database", id) // variable to store query results - r := new(Dashboard) + d := new(types.Dashboard) // send query to the database and store result in variable err := e.client. Table(constants.TableDashboard). Where("id = ?", id). - Take(r). + Take(d). Error if err != nil { return nil, err } - return r.ToAPI(), nil + return d.ToAPI(), nil } diff --git a/database/dashboard/get_test.go b/database/dashboard/get_test.go index 79664ad91..3727328a6 100644 --- a/database/dashboard/get_test.go +++ b/database/dashboard/get_test.go @@ -10,6 +10,7 @@ import ( "github.com/google/go-cmp/cmp" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestRepo_Engine_GetDashboard(t *testing.T) { @@ -26,7 +27,7 @@ func TestRepo_Engine_GetDashboard(t *testing.T) { _admin.SetActive(true) _admins := []*api.User{_admin} - _dashboard := testDashboard() + _dashboard := testutils.APIDashboard() _dashboard.SetID("c8da1302-07d6-11ea-882f-4893bca275b8") _dashboard.SetName("dash") _dashboard.SetCreatedAt(1) diff --git a/database/dashboard/update.go b/database/dashboard/update.go index 85947f545..f05fe3e28 100644 --- a/database/dashboard/update.go +++ b/database/dashboard/update.go @@ -9,6 +9,7 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/constants" + "github.com/go-vela/server/database/types" ) // UpdateDashboard updates an existing dashboard in the database. @@ -17,7 +18,7 @@ func (e *engine) UpdateDashboard(ctx context.Context, d *api.Dashboard) (*api.Da "dashboard": d.GetID(), }).Tracef("creating dashboard %s in the database", d.GetID()) - dashboard := FromAPI(d) + dashboard := types.DashboardFromAPI(d) err := dashboard.Validate() if err != nil { diff --git a/database/dashboard/update_test.go b/database/dashboard/update_test.go index adf1627e7..95437613e 100644 --- a/database/dashboard/update_test.go +++ b/database/dashboard/update_test.go @@ -10,6 +10,7 @@ import ( "github.com/google/go-cmp/cmp" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestDashboard_Engine_UpdateDashboard(t *testing.T) { @@ -26,7 +27,7 @@ func TestDashboard_Engine_UpdateDashboard(t *testing.T) { _admin.SetActive(true) _admins := []*api.User{_admin} - _dashboard := testDashboard() + _dashboard := testutils.APIDashboard() _dashboard.SetID("c8da1302-07d6-11ea-882f-4893bca275b8") _dashboard.SetName("dash") _dashboard.SetCreatedAt(1) diff --git a/database/deployment/count_repo_test.go b/database/deployment/count_repo_test.go index d358aad3f..775361570 100644 --- a/database/deployment/count_repo_test.go +++ b/database/deployment/count_repo_test.go @@ -9,6 +9,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) @@ -16,7 +17,7 @@ func TestDeployment_Engine_CountDeploymentsForRepo(t *testing.T) { builds := []*library.Build{} // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) @@ -31,7 +32,7 @@ func TestDeployment_Engine_CountDeploymentsForRepo(t *testing.T) { _deploymentOne.SetCreatedBy("octocat") _deploymentOne.SetBuilds(builds) - _deploymentTwo := testDeployment() + _deploymentTwo := testutils.APIDeployment() _deploymentTwo.SetID(2) _deploymentTwo.SetRepoID(2) _deploymentTwo.SetNumber(2) @@ -46,7 +47,7 @@ func TestDeployment_Engine_CountDeploymentsForRepo(t *testing.T) { _deploymentTwo.SetCreatedBy("octocat") _deploymentTwo.SetBuilds(builds) - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetOrg("foo") diff --git a/database/deployment/count_test.go b/database/deployment/count_test.go index 78a07afeb..914bb22a5 100644 --- a/database/deployment/count_test.go +++ b/database/deployment/count_test.go @@ -9,6 +9,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" "github.com/go-vela/types/raw" ) @@ -51,7 +52,7 @@ func TestDeployment_Engine_CountDeployments(t *testing.T) { builds = append(builds, buildOne) // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) @@ -66,7 +67,7 @@ func TestDeployment_Engine_CountDeployments(t *testing.T) { _deploymentOne.SetCreatedBy("octocat") _deploymentOne.SetBuilds(builds) - _deploymentTwo := testDeployment() + _deploymentTwo := testutils.APIDeployment() _deploymentTwo.SetID(2) _deploymentTwo.SetRepoID(2) _deploymentTwo.SetNumber(2) diff --git a/database/deployment/create_test.go b/database/deployment/create_test.go index f915eea0b..92a2e3448 100644 --- a/database/deployment/create_test.go +++ b/database/deployment/create_test.go @@ -8,6 +8,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) @@ -15,7 +16,7 @@ func TestDeployment_Engine_CreateDeployment(t *testing.T) { builds := []*library.Build{} // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) diff --git a/database/deployment/delete_test.go b/database/deployment/delete_test.go index 5b984bbd7..e037c684c 100644 --- a/database/deployment/delete_test.go +++ b/database/deployment/delete_test.go @@ -8,6 +8,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) @@ -15,7 +16,7 @@ func TestDeployment_Engine_DeleteDeployment(t *testing.T) { builds := []*library.Build{} // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) diff --git a/database/deployment/deployment_test.go b/database/deployment/deployment_test.go index 1aabcb6c3..6ab73474f 100644 --- a/database/deployment/deployment_test.go +++ b/database/deployment/deployment_test.go @@ -11,10 +11,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - api "github.com/go-vela/server/api/types" - "github.com/go-vela/types/library" - "github.com/go-vela/types/raw" ) func TestDeployment_New(t *testing.T) { @@ -165,48 +161,3 @@ func testSqlite(t *testing.T) *engine { return _engine } - -// testDeployment is a test helper function to create a library -// Deployment type with all fields set to their zero values. -func testDeployment() *library.Deployment { - builds := []*library.Build{} - return &library.Deployment{ - ID: new(int64), - RepoID: new(int64), - Number: new(int64), - URL: new(string), - Commit: new(string), - Ref: new(string), - Task: new(string), - Target: new(string), - Description: new(string), - Payload: new(raw.StringSliceMap), - CreatedAt: new(int64), - CreatedBy: new(string), - Builds: builds, - } -} - -// testRepo is a test helper function to create a library -// Repo type with all fields set to their zero values. -func testRepo() *api.Repo { - return &api.Repo{ - ID: new(int64), - BuildLimit: new(int64), - Timeout: new(int64), - Counter: new(int), - PipelineType: new(string), - Hash: new(string), - Org: new(string), - Name: new(string), - FullName: new(string), - Link: new(string), - Clone: new(string), - Branch: new(string), - Visibility: new(string), - PreviousName: new(string), - Private: new(bool), - Trusted: new(bool), - Active: new(bool), - } -} diff --git a/database/deployment/get_repo_test.go b/database/deployment/get_repo_test.go index 72f258182..78070f8c3 100644 --- a/database/deployment/get_repo_test.go +++ b/database/deployment/get_repo_test.go @@ -9,6 +9,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) @@ -16,7 +17,7 @@ func TestDeployment_Engine_GetDeploymentForRepo(t *testing.T) { builds := []*library.Build{} // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) @@ -31,7 +32,7 @@ func TestDeployment_Engine_GetDeploymentForRepo(t *testing.T) { _deploymentOne.SetCreatedBy("octocat") _deploymentOne.SetBuilds(builds) - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetOrg("foo") diff --git a/database/deployment/get_test.go b/database/deployment/get_test.go index 0fdb289c9..b579aeecd 100644 --- a/database/deployment/get_test.go +++ b/database/deployment/get_test.go @@ -9,6 +9,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) @@ -16,7 +17,7 @@ func TestDeployment_Engine_GetDeployment(t *testing.T) { builds := []*library.Build{} // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) diff --git a/database/deployment/list_repo_test.go b/database/deployment/list_repo_test.go index 377ee8af3..c93de0939 100644 --- a/database/deployment/list_repo_test.go +++ b/database/deployment/list_repo_test.go @@ -9,11 +9,12 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestDeployment_Engine_ListDeploymentsForRepo(t *testing.T) { - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.SetOrg("foo") _repo.SetName("bar") @@ -22,7 +23,7 @@ func TestDeployment_Engine_ListDeploymentsForRepo(t *testing.T) { builds := []*library.Build{} // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) @@ -37,7 +38,7 @@ func TestDeployment_Engine_ListDeploymentsForRepo(t *testing.T) { _deploymentOne.SetCreatedBy("octocat") _deploymentOne.SetBuilds(builds) - _deploymentTwo := testDeployment() + _deploymentTwo := testutils.APIDeployment() _deploymentTwo.SetID(2) _deploymentTwo.SetRepoID(2) _deploymentTwo.SetNumber(2) diff --git a/database/deployment/list_test.go b/database/deployment/list_test.go index 8b620eda4..8edefe64e 100644 --- a/database/deployment/list_test.go +++ b/database/deployment/list_test.go @@ -9,6 +9,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) @@ -16,7 +17,7 @@ func TestDeployment_Engine_ListDeployments(t *testing.T) { builds := []*library.Build{} // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) @@ -31,7 +32,7 @@ func TestDeployment_Engine_ListDeployments(t *testing.T) { _deploymentOne.SetCreatedBy("octocat") _deploymentOne.SetBuilds(builds) - _deploymentTwo := testDeployment() + _deploymentTwo := testutils.APIDeployment() _deploymentTwo.SetID(2) _deploymentTwo.SetRepoID(2) _deploymentTwo.SetNumber(2) diff --git a/database/deployment/update_test.go b/database/deployment/update_test.go index d8aaa574d..d70b3ea85 100644 --- a/database/deployment/update_test.go +++ b/database/deployment/update_test.go @@ -8,6 +8,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) @@ -15,7 +16,7 @@ func TestDeployment_Engine_UpdateDeployment(t *testing.T) { builds := []*library.Build{} // setup types - _deploymentOne := testDeployment() + _deploymentOne := testutils.APIDeployment() _deploymentOne.SetID(1) _deploymentOne.SetRepoID(1) _deploymentOne.SetNumber(1) diff --git a/database/hook/count_repo_test.go b/database/hook/count_repo_test.go index cd1592f4e..e6b8c8d43 100644 --- a/database/hook/count_repo_test.go +++ b/database/hook/count_repo_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestHook_Engine_CountHooksForRepo(t *testing.T) { // setup types - _hookOne := testHook() + _hookOne := testutils.APIHook() _hookOne.SetID(1) _hookOne.SetRepoID(1) _hookOne.SetBuildID(1) @@ -20,7 +22,7 @@ func TestHook_Engine_CountHooksForRepo(t *testing.T) { _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") _hookOne.SetWebhookID(1) - _hookTwo := testHook() + _hookTwo := testutils.APIHook() _hookTwo.SetID(2) _hookTwo.SetRepoID(2) _hookTwo.SetBuildID(2) @@ -28,7 +30,7 @@ func TestHook_Engine_CountHooksForRepo(t *testing.T) { _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") _hookTwo.SetWebhookID(1) - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetOrg("foo") diff --git a/database/hook/count_test.go b/database/hook/count_test.go index 96cc5560e..20c022217 100644 --- a/database/hook/count_test.go +++ b/database/hook/count_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestHook_Engine_CountHooks(t *testing.T) { // setup types - _hookOne := testHook() + _hookOne := testutils.APIHook() _hookOne.SetID(1) _hookOne.SetRepoID(1) _hookOne.SetBuildID(1) @@ -20,7 +22,7 @@ func TestHook_Engine_CountHooks(t *testing.T) { _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") _hookOne.SetWebhookID(1) - _hookTwo := testHook() + _hookTwo := testutils.APIHook() _hookTwo.SetID(2) _hookTwo.SetRepoID(1) _hookTwo.SetBuildID(2) diff --git a/database/hook/create_test.go b/database/hook/create_test.go index cd5b6e62e..2dd34cb10 100644 --- a/database/hook/create_test.go +++ b/database/hook/create_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestHook_Engine_CreateHook(t *testing.T) { // setup types - _hook := testHook() + _hook := testutils.APIHook() _hook.SetID(1) _hook.SetRepoID(1) _hook.SetBuildID(1) diff --git a/database/hook/delete_test.go b/database/hook/delete_test.go index cbdef043e..f89e44116 100644 --- a/database/hook/delete_test.go +++ b/database/hook/delete_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestHook_Engine_DeleteHook(t *testing.T) { // setup types - _hook := testHook() + _hook := testutils.APIHook() _hook.SetID(1) _hook.SetRepoID(1) _hook.SetBuildID(1) diff --git a/database/hook/get_repo_test.go b/database/hook/get_repo_test.go index 2ee8de362..df2dc6d7f 100644 --- a/database/hook/get_repo_test.go +++ b/database/hook/get_repo_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestHook_Engine_GetHookForRepo(t *testing.T) { // setup types - _hook := testHook() + _hook := testutils.APIHook() _hook.SetID(1) _hook.SetRepoID(1) _hook.SetBuildID(1) @@ -22,7 +23,7 @@ func TestHook_Engine_GetHookForRepo(t *testing.T) { _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") _hook.SetWebhookID(1) - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetOrg("foo") diff --git a/database/hook/get_test.go b/database/hook/get_test.go index 004baa3fe..a33f144c2 100644 --- a/database/hook/get_test.go +++ b/database/hook/get_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestHook_Engine_GetHook(t *testing.T) { // setup types - _hook := testHook() + _hook := testutils.APIHook() _hook.SetID(1) _hook.SetRepoID(1) _hook.SetBuildID(1) diff --git a/database/hook/get_webhook_test.go b/database/hook/get_webhook_test.go index 57bd3628f..975c568af 100644 --- a/database/hook/get_webhook_test.go +++ b/database/hook/get_webhook_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestHook_Engine_GetHookByWebhookID(t *testing.T) { // setup types - _hook := testHook() + _hook := testutils.APIHook() _hook.SetID(1) _hook.SetRepoID(1) _hook.SetBuildID(1) diff --git a/database/hook/hook_test.go b/database/hook/hook_test.go index cb66db823..615572398 100644 --- a/database/hook/hook_test.go +++ b/database/hook/hook_test.go @@ -11,9 +11,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - api "github.com/go-vela/server/api/types" - "github.com/go-vela/types/library" ) func TestHook_New(t *testing.T) { @@ -164,48 +161,3 @@ func testSqlite(t *testing.T) *engine { return _engine } - -// testHook is a test helper function to create a library -// Hook type with all fields set to their zero values. -func testHook() *library.Hook { - return &library.Hook{ - ID: new(int64), - RepoID: new(int64), - BuildID: new(int64), - Number: new(int), - SourceID: new(string), - Created: new(int64), - Host: new(string), - Event: new(string), - EventAction: new(string), - Branch: new(string), - Error: new(string), - Status: new(string), - Link: new(string), - WebhookID: new(int64), - } -} - -// testRepo is a test helper function to create a library -// Repo type with all fields set to their zero values. -func testRepo() *api.Repo { - return &api.Repo{ - ID: new(int64), - BuildLimit: new(int64), - Timeout: new(int64), - Counter: new(int), - PipelineType: new(string), - Hash: new(string), - Org: new(string), - Name: new(string), - FullName: new(string), - Link: new(string), - Clone: new(string), - Branch: new(string), - Visibility: new(string), - PreviousName: new(string), - Private: new(bool), - Trusted: new(bool), - Active: new(bool), - } -} diff --git a/database/hook/last_repo_test.go b/database/hook/last_repo_test.go index a9366d259..277932f2d 100644 --- a/database/hook/last_repo_test.go +++ b/database/hook/last_repo_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestHook_Engine_LastHookForRepo(t *testing.T) { // setup types - _hook := testHook() + _hook := testutils.APIHook() _hook.SetID(1) _hook.SetRepoID(1) _hook.SetBuildID(1) @@ -22,7 +23,7 @@ func TestHook_Engine_LastHookForRepo(t *testing.T) { _hook.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") _hook.SetWebhookID(1) - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetOrg("foo") diff --git a/database/hook/list_repo_test.go b/database/hook/list_repo_test.go index c9698c0eb..b68a41747 100644 --- a/database/hook/list_repo_test.go +++ b/database/hook/list_repo_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestHook_Engine_ListHooksForRepo(t *testing.T) { // setup types - _hookOne := testHook() + _hookOne := testutils.APIHook() _hookOne.SetID(1) _hookOne.SetRepoID(1) _hookOne.SetBuildID(1) @@ -22,7 +23,7 @@ func TestHook_Engine_ListHooksForRepo(t *testing.T) { _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") _hookOne.SetWebhookID(1) - _hookTwo := testHook() + _hookTwo := testutils.APIHook() _hookTwo.SetID(2) _hookTwo.SetRepoID(1) _hookTwo.SetBuildID(2) @@ -30,7 +31,7 @@ func TestHook_Engine_ListHooksForRepo(t *testing.T) { _hookTwo.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") _hookTwo.SetWebhookID(1) - _repo := testRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetOrg("foo") diff --git a/database/hook/list_test.go b/database/hook/list_test.go index 79c788e0a..89098751d 100644 --- a/database/hook/list_test.go +++ b/database/hook/list_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestHook_Engine_ListHooks(t *testing.T) { // setup types - _hookOne := testHook() + _hookOne := testutils.APIHook() _hookOne.SetID(1) _hookOne.SetRepoID(1) _hookOne.SetBuildID(1) @@ -22,7 +23,7 @@ func TestHook_Engine_ListHooks(t *testing.T) { _hookOne.SetSourceID("c8da1302-07d6-11ea-882f-4893bca275b8") _hookOne.SetWebhookID(1) - _hookTwo := testHook() + _hookTwo := testutils.APIHook() _hookTwo.SetID(2) _hookTwo.SetRepoID(1) _hookTwo.SetBuildID(2) diff --git a/database/hook/update_test.go b/database/hook/update_test.go index 44828b5db..72982b6c0 100644 --- a/database/hook/update_test.go +++ b/database/hook/update_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestHook_Engine_UpdateHook(t *testing.T) { // setup types - _hook := testHook() + _hook := testutils.APIHook() _hook.SetID(1) _hook.SetRepoID(1) _hook.SetBuildID(1) diff --git a/database/integration_test.go b/database/integration_test.go index aa00b260c..36e2cb5a6 100644 --- a/database/integration_test.go +++ b/database/integration_test.go @@ -25,6 +25,7 @@ import ( "github.com/go-vela/server/database/secret" "github.com/go-vela/server/database/service" "github.com/go-vela/server/database/step" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/server/database/user" "github.com/go-vela/server/database/worker" "github.com/go-vela/types/constants" @@ -34,7 +35,7 @@ import ( // Resources represents the object containing test resources. type Resources struct { - Builds []*library.Build + Builds []*api.Build Dashboards []*api.Dashboard Deployments []*library.Deployment Executables []*library.BuildExecutable @@ -175,6 +176,14 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { methods[element.Method(i).Name] = false } + // create the users for build related functions (owners of repos) + for _, user := range resources.Users { + _, err := db.CreateUser(context.TODO(), user) + if err != nil { + t.Errorf("unable to create user %d: %v", user.GetID(), err) + } + } + // create the repos for build related functions for _, repo := range resources.Repos { _, err := db.CreateRepo(context.TODO(), repo) @@ -183,19 +192,19 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { } } - buildOne := new(library.BuildQueue) + buildOne := new(api.QueueBuild) buildOne.SetCreated(1563474076) buildOne.SetFullName("github/octocat") buildOne.SetNumber(1) buildOne.SetStatus("running") - buildTwo := new(library.BuildQueue) + buildTwo := new(api.QueueBuild) buildTwo.SetCreated(1563474076) buildTwo.SetFullName("github/octocat") buildTwo.SetNumber(2) buildTwo.SetStatus("running") - queueBuilds := []*library.BuildQueue{buildOne, buildTwo} + queueBuilds := []*api.QueueBuild{buildOne, buildTwo} // create the builds for _, build := range resources.Builds { @@ -287,7 +296,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { if int(count) != len(resources.Builds) { t.Errorf("ListBuildsForRepo() is %v, want %v", count, len(resources.Builds)) } - if diff := cmp.Diff([]*library.Build{resources.Builds[1], resources.Builds[0]}, list); diff != "" { + if diff := cmp.Diff([]*api.Build{resources.Builds[1], resources.Builds[0]}, list); diff != "" { t.Errorf("ListBuildsForRepo() mismatch (-want +got):\n%s", diff) } methods["ListBuildsForRepo"] = true @@ -299,8 +308,14 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { if len(list) != 1 { t.Errorf("Number of results for ListBuildsForDashboardRepo() is %v, want %v", len(list), 1) } - if !cmp.Equal(list, []*library.Build{resources.Builds[0]}) { - t.Errorf("ListBuildsForDashboardRepo() is %v, want %v", list, []*library.Build{resources.Builds[0]}) + + // ListBuildsForDashboardRepo does not contain nested repo + wantBuild := *resources.Builds[0] + wantBuild.Repo = testutils.APIRepo() + wantBuild.Repo.Owner = testutils.APIUser().Crop() + + if diff := cmp.Diff([]*api.Build{&wantBuild}, list); diff != "" { + t.Errorf("ListBuildsForDashboardRepo() mismatch (-want +got):\n%s", diff) } methods["ListBuildsForDashboardRepo"] = true @@ -312,7 +327,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { if int(count) != len(resources.Builds) { t.Errorf("ListPendingAndRunningBuildsForRepo() is %v, want %v", count, len(resources.Builds)) } - if diff := cmp.Diff([]*library.Build{resources.Builds[0], resources.Builds[1]}, list); diff != "" { + if diff := cmp.Diff([]*api.Build{resources.Builds[0], resources.Builds[1]}, list); diff != "" { t.Errorf("ListPendingAndRunningBuildsForRepo() mismatch (-want +got):\n%s", diff) } methods["ListPendingAndRunningBuildsForRepo"] = true @@ -339,7 +354,7 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { // lookup the builds by repo and number for _, build := range resources.Builds { - repo := resources.Repos[build.GetRepoID()-1] + repo := resources.Repos[build.GetRepo().GetID()-1] got, err = db.GetBuildForRepo(context.TODO(), repo, build.GetNumber()) if err != nil { t.Errorf("unable to get build %d for repo %d: %v", build.GetID(), repo.GetID(), err) @@ -397,6 +412,14 @@ func testBuilds(t *testing.T, db Interface, resources *Resources) { } } + // delete the users for the build related functions + for _, user := range resources.Users { + err = db.DeleteUser(context.TODO(), user) + if err != nil { + t.Errorf("unable to delete user %d: %v", user.GetID(), err) + } + } + // ensure we called all the methods we expected to for method, called := range methods { if !called { @@ -462,8 +485,14 @@ func testDashboards(t *testing.T, db Interface, resources *Resources) { t.Errorf("unable to update dashboard %s: %v", dashboard.GetID(), err) } - if !cmp.Equal(got, dashboard, CmpOptApproxUpdatedAt()) { - t.Errorf("UpdateDashboard() is %v, want %v", got, dashboard) + // JSON marshaling does not include comparing token due to `-` struct tag + cmpAdmins := got.GetAdmins() + for i, admin := range cmpAdmins { + admin.SetToken(resources.Users[i].GetToken()) + } + + if diff := cmp.Diff(dashboard, got, CmpOptApproxUpdatedAt()); diff != "" { + t.Errorf("UpdateDashboard() mismatch (-want +got):\n%s", diff) } } methods["UpdateDashboard"] = true @@ -2123,20 +2152,59 @@ func newResources() *Resources { userTwo.SetToken("superSecretToken") userTwo.SetRefreshToken("superSecretRefreshToken") userTwo.SetFavorites([]string{"github/octocat"}) + userTwo.SetDashboards([]string{"45bcf19b-c151-4e2d-b8c6-80a62ba2eae7"}) userTwo.SetActive(true) userTwo.SetAdmin(false) - userTwo.SetDashboards([]string{"45bcf19b-c151-4e2d-b8c6-80a62ba2eae7", "ba657dab-bc6e-421f-9188-86272bd0069a"}) - // crop and set "-" JSON tag fields to nil for dashboard admins - dashboardAdmins := []*api.User{userOne.Crop(), userTwo.Crop()} - for _, admin := range dashboardAdmins { - admin.Token = nil - admin.RefreshToken = nil - } + repoOne := new(api.Repo) + repoOne.SetID(1) + repoOne.SetOwner(userOne.Crop()) + repoOne.SetHash("MzM4N2MzMDAtNmY4Mi00OTA5LWFhZDAtNWIzMTlkNTJkODMy") + repoOne.SetOrg("github") + repoOne.SetName("octocat") + repoOne.SetFullName("github/octocat") + repoOne.SetLink("https://github.com/github/octocat") + repoOne.SetClone("https://github.com/github/octocat.git") + repoOne.SetBranch("main") + repoOne.SetTopics([]string{"cloud", "security"}) + repoOne.SetBuildLimit(10) + repoOne.SetTimeout(30) + repoOne.SetCounter(0) + repoOne.SetVisibility("public") + repoOne.SetPrivate(false) + repoOne.SetTrusted(false) + repoOne.SetActive(true) + repoOne.SetPipelineType("") + repoOne.SetPreviousName("") + repoOne.SetApproveBuild(constants.ApproveNever) + repoOne.SetAllowEvents(api.NewEventsFromMask(1)) - buildOne := new(library.Build) + repoTwo := new(api.Repo) + repoTwo.SetID(2) + repoTwo.SetOwner(userOne.Crop()) + repoTwo.SetHash("MzM4N2MzMDAtNmY4Mi00OTA5LWFhZDAtNWIzMTlkNTJkODMy") + repoTwo.SetOrg("github") + repoTwo.SetName("octokitty") + repoTwo.SetFullName("github/octokitty") + repoTwo.SetLink("https://github.com/github/octokitty") + repoTwo.SetClone("https://github.com/github/octokitty.git") + repoTwo.SetBranch("main") + repoTwo.SetTopics([]string{"cloud", "security"}) + repoTwo.SetBuildLimit(10) + repoTwo.SetTimeout(30) + repoTwo.SetCounter(0) + repoTwo.SetVisibility("public") + repoTwo.SetPrivate(false) + repoTwo.SetTrusted(false) + repoTwo.SetActive(true) + repoTwo.SetPipelineType("") + repoTwo.SetPreviousName("") + repoTwo.SetApproveBuild(constants.ApproveForkAlways) + repoTwo.SetAllowEvents(api.NewEventsFromMask(1)) + + buildOne := new(api.Build) buildOne.SetID(1) - buildOne.SetRepoID(1) + buildOne.SetRepo(repoOne) buildOne.SetPipelineID(1) buildOne.SetNumber(1) buildOne.SetParent(1) @@ -2170,9 +2238,9 @@ func newResources() *Resources { buildOne.SetApprovedAt(1563474078) buildOne.SetApprovedBy("OctoCat") - buildTwo := new(library.Build) + buildTwo := new(api.Build) buildTwo.SetID(2) - buildTwo.SetRepoID(1) + buildTwo.SetRepo(repoOne) buildTwo.SetPipelineID(1) buildTwo.SetNumber(2) buildTwo.SetParent(1) @@ -2212,6 +2280,13 @@ func newResources() *Resources { dashRepo.SetBranches([]string{"main"}) dashRepo.SetEvents([]string{"push"}) + // crop and set "-" JSON tag fields to nil for dashboard admins + dashboardAdmins := []*api.User{userOne.Crop(), userTwo.Crop()} + for _, admin := range dashboardAdmins { + admin.Token = nil + admin.RefreshToken = nil + } + dashboardOne := new(api.Dashboard) dashboardOne.SetID("ba657dab-bc6e-421f-9188-86272bd0069a") dashboardOne.SetName("vela") @@ -2387,52 +2462,6 @@ func newResources() *Resources { pipelineTwo.SetTemplates(false) pipelineTwo.SetData([]byte("version: 1")) - repoOne := new(api.Repo) - repoOne.SetID(1) - repoOne.SetOwner(userOne.Crop()) - repoOne.SetHash("MzM4N2MzMDAtNmY4Mi00OTA5LWFhZDAtNWIzMTlkNTJkODMy") - repoOne.SetOrg("github") - repoOne.SetName("octocat") - repoOne.SetFullName("github/octocat") - repoOne.SetLink("https://github.com/github/octocat") - repoOne.SetClone("https://github.com/github/octocat.git") - repoOne.SetBranch("main") - repoOne.SetTopics([]string{"cloud", "security"}) - repoOne.SetBuildLimit(10) - repoOne.SetTimeout(30) - repoOne.SetCounter(0) - repoOne.SetVisibility("public") - repoOne.SetPrivate(false) - repoOne.SetTrusted(false) - repoOne.SetActive(true) - repoOne.SetPipelineType("") - repoOne.SetPreviousName("") - repoOne.SetApproveBuild(constants.ApproveNever) - repoOne.SetAllowEvents(api.NewEventsFromMask(1)) - - repoTwo := new(api.Repo) - repoTwo.SetID(2) - repoTwo.SetOwner(userOne.Crop()) - repoTwo.SetHash("MzM4N2MzMDAtNmY4Mi00OTA5LWFhZDAtNWIzMTlkNTJkODMy") - repoTwo.SetOrg("github") - repoTwo.SetName("octokitty") - repoTwo.SetFullName("github/octokitty") - repoTwo.SetLink("https://github.com/github/octokitty") - repoTwo.SetClone("https://github.com/github/octokitty.git") - repoTwo.SetBranch("main") - repoTwo.SetTopics([]string{"cloud", "security"}) - repoTwo.SetBuildLimit(10) - repoTwo.SetTimeout(30) - repoTwo.SetCounter(0) - repoTwo.SetVisibility("public") - repoTwo.SetPrivate(false) - repoTwo.SetTrusted(false) - repoTwo.SetActive(true) - repoTwo.SetPipelineType("") - repoTwo.SetPreviousName("") - repoTwo.SetApproveBuild(constants.ApproveForkAlways) - repoTwo.SetAllowEvents(api.NewEventsFromMask(1)) - scheduleOne := new(library.Schedule) scheduleOne.SetID(1) scheduleOne.SetRepoID(1) @@ -2582,10 +2611,10 @@ func newResources() *Resources { stepTwo.SetDistribution("linux") stepTwo.SetReportAs("test") - _bPartialOne := new(library.Build) + _bPartialOne := new(api.Build) _bPartialOne.SetID(1) - _bPartialTwo := new(library.Build) + _bPartialTwo := new(api.Build) _bPartialTwo.SetID(2) workerOne := new(api.Worker) @@ -2596,7 +2625,7 @@ func newResources() *Resources { workerOne.SetActive(true) workerOne.SetStatus("available") workerOne.SetLastStatusUpdateAt(time.Now().UTC().Unix()) - workerOne.SetRunningBuilds([]*library.Build{_bPartialOne}) + workerOne.SetRunningBuilds([]*api.Build{_bPartialOne}) workerOne.SetLastBuildStartedAt(time.Now().UTC().Unix()) workerOne.SetLastBuildFinishedAt(time.Now().UTC().Unix()) workerOne.SetLastCheckedIn(time.Now().UTC().Unix() - 60) @@ -2610,14 +2639,14 @@ func newResources() *Resources { workerTwo.SetActive(true) workerTwo.SetStatus("available") workerTwo.SetLastStatusUpdateAt(time.Now().UTC().Unix()) - workerTwo.SetRunningBuilds([]*library.Build{_bPartialTwo}) + workerTwo.SetRunningBuilds([]*api.Build{_bPartialTwo}) workerTwo.SetLastBuildStartedAt(time.Now().UTC().Unix()) workerTwo.SetLastBuildFinishedAt(time.Now().UTC().Unix()) workerTwo.SetLastCheckedIn(time.Now().UTC().Unix() - 60) workerTwo.SetBuildLimit(1) return &Resources{ - Builds: []*library.Build{buildOne, buildTwo}, + Builds: []*api.Build{buildOne, buildTwo}, Dashboards: []*api.Dashboard{dashboardOne, dashboardTwo}, Deployments: []*library.Deployment{deploymentOne, deploymentTwo}, Executables: []*library.BuildExecutable{executableOne, executableTwo}, diff --git a/database/log/count_build.go b/database/log/count_build.go index 168d9e1c1..75145d5e3 100644 --- a/database/log/count_build.go +++ b/database/log/count_build.go @@ -5,12 +5,12 @@ package log import ( "context" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) // CountLogsForBuild gets the count of logs by build ID from the database. -func (e *engine) CountLogsForBuild(ctx context.Context, b *library.Build) (int64, error) { +func (e *engine) CountLogsForBuild(ctx context.Context, b *api.Build) (int64, error) { e.logger.Tracef("getting count of logs for build %d from the database", b.GetID()) // variable to store query results diff --git a/database/log/count_build_test.go b/database/log/count_build_test.go index c66422134..ca05016fb 100644 --- a/database/log/count_build_test.go +++ b/database/log/count_build_test.go @@ -8,26 +8,31 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestLog_Engine_CountLogsForBuild(t *testing.T) { // setup types - _service := testLog() + _service := testutils.APILog() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) _service.SetServiceID(1) - _step := testLog() + _step := testutils.APILog() _step.SetID(2) _step.SetRepoID(1) _step.SetBuildID(1) _step.SetStepID(1) - _build := testBuild() + _repo := testutils.APIRepo() + _repo.SetID(1) + + _build := testutils.APIBuild() _build.SetID(1) _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(_repo) _build.SetNumber(1) _postgres, _mock := testPostgres(t) diff --git a/database/log/count_test.go b/database/log/count_test.go index cb7f516dc..49ee80de5 100644 --- a/database/log/count_test.go +++ b/database/log/count_test.go @@ -8,17 +8,19 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestLog_Engine_CountLogs(t *testing.T) { // setup types - _service := testLog() + _service := testutils.APILog() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) _service.SetServiceID(1) - _step := testLog() + _step := testutils.APILog() _step.SetID(2) _step.SetRepoID(1) _step.SetBuildID(1) diff --git a/database/log/create_test.go b/database/log/create_test.go index 9f6852ab9..3b86fbe44 100644 --- a/database/log/create_test.go +++ b/database/log/create_test.go @@ -8,18 +8,19 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestLog_Engine_CreateLog(t *testing.T) { // setup types - _service := testLog() + _service := testutils.APILog() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) _service.SetServiceID(1) - _step := testLog() + _step := testutils.APILog() _step.SetID(2) _step.SetRepoID(1) _step.SetBuildID(1) diff --git a/database/log/delete_test.go b/database/log/delete_test.go index 3b3000fc6..610f0c2cd 100644 --- a/database/log/delete_test.go +++ b/database/log/delete_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestLog_Engine_DeleteLog(t *testing.T) { // setup types - _log := testLog() + _log := testutils.APILog() _log.SetID(1) _log.SetRepoID(1) _log.SetBuildID(1) diff --git a/database/log/get_service_test.go b/database/log/get_service_test.go index 6b7c89529..b4ae5efe5 100644 --- a/database/log/get_service_test.go +++ b/database/log/get_service_test.go @@ -9,19 +9,20 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestLog_Engine_GetLogForService(t *testing.T) { // setup types - _log := testLog() + _log := testutils.APILog() _log.SetID(1) _log.SetRepoID(1) _log.SetBuildID(1) _log.SetServiceID(1) _log.SetData([]byte{}) - _service := testService() + _service := testutils.APIService() _service.SetID(1) _service.SetID(1) _service.SetRepoID(1) diff --git a/database/log/get_step_test.go b/database/log/get_step_test.go index 5606ef79b..68073bf85 100644 --- a/database/log/get_step_test.go +++ b/database/log/get_step_test.go @@ -9,19 +9,20 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestLog_Engine_GetLogForStep(t *testing.T) { // setup types - _log := testLog() + _log := testutils.APILog() _log.SetID(1) _log.SetRepoID(1) _log.SetBuildID(1) _log.SetStepID(1) _log.SetData([]byte{}) - _step := testStep() + _step := testutils.APIStep() _step.SetID(1) _step.SetID(1) _step.SetRepoID(1) diff --git a/database/log/get_test.go b/database/log/get_test.go index 33028ad7d..d2263704f 100644 --- a/database/log/get_test.go +++ b/database/log/get_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestLog_Engine_GetLog(t *testing.T) { // setup types - _log := testLog() + _log := testutils.APILog() _log.SetID(1) _log.SetRepoID(1) _log.SetBuildID(1) diff --git a/database/log/interface.go b/database/log/interface.go index 92f5d6cdd..97ace05c6 100644 --- a/database/log/interface.go +++ b/database/log/interface.go @@ -5,6 +5,7 @@ package log import ( "context" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/library" ) @@ -29,7 +30,7 @@ type LogInterface interface { // CountLogs defines a function that gets the count of all logs. CountLogs(context.Context) (int64, error) // CountLogsForBuild defines a function that gets the count of logs by build ID. - CountLogsForBuild(context.Context, *library.Build) (int64, error) + CountLogsForBuild(context.Context, *api.Build) (int64, error) // CreateLog defines a function that creates a new log. CreateLog(context.Context, *library.Log) error // DeleteLog defines a function that deletes an existing log. @@ -43,7 +44,7 @@ type LogInterface interface { // ListLogs defines a function that gets a list of all logs. ListLogs(context.Context) ([]*library.Log, error) // ListLogsForBuild defines a function that gets a list of logs by build ID. - ListLogsForBuild(context.Context, *library.Build, int, int) ([]*library.Log, int64, error) + ListLogsForBuild(context.Context, *api.Build, int, int) ([]*library.Log, int64, error) // UpdateLog defines a function that updates an existing log. UpdateLog(context.Context, *library.Log) error } diff --git a/database/log/list_build.go b/database/log/list_build.go index 183b1f167..f5619d40b 100644 --- a/database/log/list_build.go +++ b/database/log/list_build.go @@ -5,13 +5,14 @@ package log import ( "context" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // ListLogsForBuild gets a list of logs by build ID from the database. -func (e *engine) ListLogsForBuild(ctx context.Context, b *library.Build, page, perPage int) ([]*library.Log, int64, error) { +func (e *engine) ListLogsForBuild(ctx context.Context, b *api.Build, page, perPage int) ([]*library.Log, int64, error) { e.logger.Tracef("listing logs for build %d from the database", b.GetID()) // variables to store query results and return value diff --git a/database/log/list_build_test.go b/database/log/list_build_test.go index 04f4f6efc..e4b9038cd 100644 --- a/database/log/list_build_test.go +++ b/database/log/list_build_test.go @@ -9,29 +9,33 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestLog_Engine_ListLogsForBuild(t *testing.T) { // setup types - _service := testLog() + _service := testutils.APILog() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) _service.SetServiceID(1) _service.SetData([]byte{}) - _step := testLog() + _step := testutils.APILog() _step.SetID(2) _step.SetRepoID(1) _step.SetBuildID(1) _step.SetStepID(1) _step.SetData([]byte{}) - _build := testBuild() + _repo := testutils.APIRepo() + _repo.SetID(1) + + _build := testutils.APIBuild() _build.SetID(1) _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(_repo) _build.SetNumber(1) _postgres, _mock := testPostgres(t) diff --git a/database/log/list_test.go b/database/log/list_test.go index 605ed26df..6371c9fd2 100644 --- a/database/log/list_test.go +++ b/database/log/list_test.go @@ -9,19 +9,20 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestLog_Engine_ListLogs(t *testing.T) { // setup types - _service := testLog() + _service := testutils.APILog() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) _service.SetServiceID(1) _service.SetData([]byte{}) - _step := testLog() + _step := testutils.APILog() _step.SetID(2) _step.SetRepoID(1) _step.SetBuildID(1) diff --git a/database/log/log_test.go b/database/log/log_test.go index 86862bbc2..528dba1e2 100644 --- a/database/log/log_test.go +++ b/database/log/log_test.go @@ -12,8 +12,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - "github.com/go-vela/types/library" ) func TestLog_New(t *testing.T) { @@ -177,98 +175,3 @@ type AnyArgument struct{} func (a AnyArgument) Match(_ driver.Value) bool { return true } - -// testBuild is a test helper function to create a library -// Build type with all fields set to their zero values. -func testBuild() *library.Build { - return &library.Build{ - ID: new(int64), - RepoID: new(int64), - PipelineID: new(int64), - Number: new(int), - Parent: new(int), - Event: new(string), - EventAction: new(string), - Status: new(string), - Error: new(string), - Enqueued: new(int64), - Created: new(int64), - Started: new(int64), - Finished: new(int64), - Deploy: new(string), - Clone: new(string), - Source: new(string), - Title: new(string), - Message: new(string), - Commit: new(string), - Sender: new(string), - Author: new(string), - Email: new(string), - Link: new(string), - Branch: new(string), - Ref: new(string), - BaseRef: new(string), - HeadRef: new(string), - Host: new(string), - Runtime: new(string), - Distribution: new(string), - } -} - -// testLog is a test helper function to create a library -// Log type with all fields set to their zero values. -func testLog() *library.Log { - return &library.Log{ - ID: new(int64), - RepoID: new(int64), - BuildID: new(int64), - ServiceID: new(int64), - StepID: new(int64), - Data: new([]byte), - } -} - -// testService is a test helper function to create a library -// Service type with all fields set to their zero values. -func testService() *library.Service { - return &library.Service{ - ID: new(int64), - BuildID: new(int64), - RepoID: new(int64), - Number: new(int), - Name: new(string), - Image: new(string), - Status: new(string), - Error: new(string), - ExitCode: new(int), - Created: new(int64), - Started: new(int64), - Finished: new(int64), - Host: new(string), - Runtime: new(string), - Distribution: new(string), - } -} - -// testStep is a test helper function to create a library -// Step type with all fields set to their zero values. -func testStep() *library.Step { - return &library.Step{ - ID: new(int64), - BuildID: new(int64), - RepoID: new(int64), - Number: new(int), - Name: new(string), - Image: new(string), - Stage: new(string), - Status: new(string), - Error: new(string), - ExitCode: new(int), - Created: new(int64), - Started: new(int64), - Finished: new(int64), - Host: new(string), - Runtime: new(string), - Distribution: new(string), - } -} diff --git a/database/log/update_test.go b/database/log/update_test.go index 67f3313bc..ae2ca53f0 100644 --- a/database/log/update_test.go +++ b/database/log/update_test.go @@ -8,19 +8,20 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestLog_Engine_UpdateLog(t *testing.T) { // setup types - _service := testLog() + _service := testutils.APILog() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) _service.SetServiceID(1) _service.SetData([]byte{}) - _step := testLog() + _step := testutils.APILog() _step.SetID(2) _step.SetRepoID(1) _step.SetBuildID(1) diff --git a/database/pipeline/count_repo_test.go b/database/pipeline/count_repo_test.go index 729b25955..ae306e9e5 100644 --- a/database/pipeline/count_repo_test.go +++ b/database/pipeline/count_repo_test.go @@ -10,11 +10,12 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { // setup types - _pipelineOne := testPipeline() + _pipelineOne := testutils.APIPipeline() _pipelineOne.SetID(1) _pipelineOne.SetRepoID(1) _pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") @@ -22,7 +23,7 @@ func TestPipeline_Engine_CountPipelinesForRepo(t *testing.T) { _pipelineOne.SetType("yaml") _pipelineOne.SetVersion("1") - _pipelineTwo := testPipeline() + _pipelineTwo := testutils.APIPipeline() _pipelineTwo.SetID(2) _pipelineTwo.SetRepoID(1) _pipelineTwo.SetCommit("a49aaf4afae6431a79239c95247a2b169fd9f067") diff --git a/database/pipeline/count_test.go b/database/pipeline/count_test.go index 829acfd58..351e84050 100644 --- a/database/pipeline/count_test.go +++ b/database/pipeline/count_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestPipeline_Engine_CountPipelines(t *testing.T) { // setup types - _pipelineOne := testPipeline() + _pipelineOne := testutils.APIPipeline() _pipelineOne.SetID(1) _pipelineOne.SetRepoID(1) _pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") @@ -20,7 +22,7 @@ func TestPipeline_Engine_CountPipelines(t *testing.T) { _pipelineOne.SetType("yaml") _pipelineOne.SetVersion("1") - _pipelineTwo := testPipeline() + _pipelineTwo := testutils.APIPipeline() _pipelineTwo.SetID(2) _pipelineTwo.SetRepoID(2) _pipelineTwo.SetCommit("a49aaf4afae6431a79239c95247a2b169fd9f067") diff --git a/database/pipeline/create_test.go b/database/pipeline/create_test.go index f6a0b7af1..58f52ffcc 100644 --- a/database/pipeline/create_test.go +++ b/database/pipeline/create_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestPipeline_Engine_CreatePipeline(t *testing.T) { // setup types - _pipeline := testPipeline() + _pipeline := testutils.APIPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") diff --git a/database/pipeline/delete_test.go b/database/pipeline/delete_test.go index 2b141b702..35a03d463 100644 --- a/database/pipeline/delete_test.go +++ b/database/pipeline/delete_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestPipeline_Engine_DeletePipeline(t *testing.T) { // setup types - _pipeline := testPipeline() + _pipeline := testutils.APIPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") diff --git a/database/pipeline/get_repo_test.go b/database/pipeline/get_repo_test.go index 69ffe7751..d62612cd2 100644 --- a/database/pipeline/get_repo_test.go +++ b/database/pipeline/get_repo_test.go @@ -10,12 +10,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestPipeline_Engine_GetPipelineForRepo(t *testing.T) { // setup types - _pipeline := testPipeline() + _pipeline := testutils.APIPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") diff --git a/database/pipeline/get_test.go b/database/pipeline/get_test.go index 614b6a7c9..c24f97da0 100644 --- a/database/pipeline/get_test.go +++ b/database/pipeline/get_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestPipeline_Engine_GetPipeline(t *testing.T) { // setup types - _pipeline := testPipeline() + _pipeline := testutils.APIPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") diff --git a/database/pipeline/list_repo_test.go b/database/pipeline/list_repo_test.go index 7daa96547..4acc87e20 100644 --- a/database/pipeline/list_repo_test.go +++ b/database/pipeline/list_repo_test.go @@ -10,12 +10,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { // setup types - _pipelineOne := testPipeline() + _pipelineOne := testutils.APIPipeline() _pipelineOne.SetID(1) _pipelineOne.SetRepoID(1) _pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") @@ -24,7 +25,7 @@ func TestPipeline_Engine_ListPipelinesForRepo(t *testing.T) { _pipelineOne.SetVersion("1") _pipelineOne.SetData([]byte("foo")) - _pipelineTwo := testPipeline() + _pipelineTwo := testutils.APIPipeline() _pipelineTwo.SetID(2) _pipelineTwo.SetRepoID(1) _pipelineTwo.SetCommit("a49aaf4afae6431a79239c95247a2b169fd9f067") diff --git a/database/pipeline/list_test.go b/database/pipeline/list_test.go index f356afe82..b485bab6f 100644 --- a/database/pipeline/list_test.go +++ b/database/pipeline/list_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestPipeline_Engine_ListPipelines(t *testing.T) { // setup types - _pipelineOne := testPipeline() + _pipelineOne := testutils.APIPipeline() _pipelineOne.SetID(1) _pipelineOne.SetRepoID(1) _pipelineOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") @@ -23,7 +24,7 @@ func TestPipeline_Engine_ListPipelines(t *testing.T) { _pipelineOne.SetVersion("1") _pipelineOne.SetData([]byte("foo")) - _pipelineTwo := testPipeline() + _pipelineTwo := testutils.APIPipeline() _pipelineTwo.SetID(2) _pipelineTwo.SetRepoID(2) _pipelineTwo.SetCommit("a49aaf4afae6431a79239c95247a2b169fd9f067") diff --git a/database/pipeline/pipeline_test.go b/database/pipeline/pipeline_test.go index 76abee9ed..e748b21f1 100644 --- a/database/pipeline/pipeline_test.go +++ b/database/pipeline/pipeline_test.go @@ -13,8 +13,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - "github.com/go-vela/types/library" ) func TestPipeline_New(t *testing.T) { @@ -174,28 +172,6 @@ func testSqlite(t *testing.T) *engine { return _engine } -// testPipeline is a test helper function to create a library -// Pipeline type with all fields set to their zero values. -func testPipeline() *library.Pipeline { - return &library.Pipeline{ - ID: new(int64), - RepoID: new(int64), - Commit: new(string), - Flavor: new(string), - Platform: new(string), - Ref: new(string), - Type: new(string), - Version: new(string), - ExternalSecrets: new(bool), - InternalSecrets: new(bool), - Services: new(bool), - Stages: new(bool), - Steps: new(bool), - Templates: new(bool), - Data: new([]byte), - } -} - // This will be used with the github.com/DATA-DOG/go-sqlmock library to compare values // that are otherwise not easily compared. These typically would be values generated // before adding or updating them in the database. diff --git a/database/pipeline/update_test.go b/database/pipeline/update_test.go index a489913ab..bb0464550 100644 --- a/database/pipeline/update_test.go +++ b/database/pipeline/update_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestPipeline_Engine_UpdatePipeline(t *testing.T) { // setup types - _pipeline := testPipeline() + _pipeline := testutils.APIPipeline() _pipeline.SetID(1) _pipeline.SetRepoID(1) _pipeline.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") diff --git a/database/repo/count_org_test.go b/database/repo/count_org_test.go index 650770e4a..1521e3025 100644 --- a/database/repo/count_org_test.go +++ b/database/repo/count_org_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestRepo_Engine_CountReposForOrg(t *testing.T) { // setup types - _repoOne := testAPIRepo() + _repoOne := testutils.APIRepo() _repoOne.SetID(1) _repoOne.GetOwner().SetID(1) _repoOne.SetHash("baz") @@ -21,7 +23,7 @@ func TestRepo_Engine_CountReposForOrg(t *testing.T) { _repoOne.SetFullName("foo/bar") _repoOne.SetVisibility("public") - _repoTwo := testAPIRepo() + _repoTwo := testutils.APIRepo() _repoTwo.SetID(2) _repoTwo.GetOwner().SetID(1) _repoTwo.SetHash("baz") diff --git a/database/repo/count_test.go b/database/repo/count_test.go index f295d885e..4803e7ea9 100644 --- a/database/repo/count_test.go +++ b/database/repo/count_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestRepo_Engine_CountRepos(t *testing.T) { // setup types - _repoOne := testAPIRepo() + _repoOne := testutils.APIRepo() _repoOne.SetID(1) _repoOne.GetOwner().SetID(1) _repoOne.SetHash("baz") @@ -21,7 +23,7 @@ func TestRepo_Engine_CountRepos(t *testing.T) { _repoOne.SetFullName("foo/bar") _repoOne.SetVisibility("public") - _repoTwo := testAPIRepo() + _repoTwo := testutils.APIRepo() _repoTwo.SetID(2) _repoTwo.GetOwner().SetID(1) _repoTwo.SetHash("baz") diff --git a/database/repo/count_user_test.go b/database/repo/count_user_test.go index 8b420ea56..543f13a1c 100644 --- a/database/repo/count_user_test.go +++ b/database/repo/count_user_test.go @@ -8,32 +8,34 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestRepo_Engine_CountReposForUser(t *testing.T) { // setup types - _repoOne := testAPIRepo() + _user := testutils.APIUser() + _user.SetID(1) + _user.SetName("foo") + + _repoOne := testutils.APIRepo() _repoOne.SetID(1) - _repoOne.GetOwner().SetID(1) + _repoOne.SetOwner(_user) _repoOne.SetHash("baz") _repoOne.SetOrg("foo") _repoOne.SetName("bar") _repoOne.SetFullName("foo/bar") _repoOne.SetVisibility("public") - _repoTwo := testAPIRepo() + _repoTwo := testutils.APIRepo() _repoTwo.SetID(2) - _repoTwo.GetOwner().SetID(1) + _repoTwo.SetOwner(_user) _repoTwo.SetHash("baz") _repoTwo.SetOrg("bar") _repoTwo.SetName("foo") _repoTwo.SetFullName("bar/foo") _repoTwo.SetVisibility("public") - _user := testOwner() - _user.SetID(1) - _user.SetName("foo") - _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() diff --git a/database/repo/create.go b/database/repo/create.go index fcfd837c6..3a604348e 100644 --- a/database/repo/create.go +++ b/database/repo/create.go @@ -10,6 +10,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -21,7 +22,7 @@ func (e *engine) CreateRepo(ctx context.Context, r *api.Repo) (*api.Repo, error) }).Tracef("creating repo %s in the database", r.GetFullName()) // cast the library type to database type - repo := FromAPI(r) + repo := types.RepoFromAPI(r) // validate the necessary fields are populated err := repo.Validate() @@ -46,8 +47,6 @@ func (e *engine) CreateRepo(ctx context.Context, r *api.Repo) (*api.Repo, error) if err != nil { // only log to preserve backwards compatibility e.logger.Errorf("unable to decrypt repo %d: %v", r.GetID(), err) - - return repo.ToAPI(), nil } // set owner to provided owner if creation successful diff --git a/database/repo/create_test.go b/database/repo/create_test.go index 67371ec5b..07b8204ab 100644 --- a/database/repo/create_test.go +++ b/database/repo/create_test.go @@ -8,11 +8,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/google/go-cmp/cmp" + + "github.com/go-vela/server/database/testutils" ) func TestRepo_Engine_CreateRepo(t *testing.T) { // setup types - _repo := testAPIRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetHash("baz") diff --git a/database/repo/delete.go b/database/repo/delete.go index 357404048..115e131c8 100644 --- a/database/repo/delete.go +++ b/database/repo/delete.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -19,7 +20,7 @@ func (e *engine) DeleteRepo(ctx context.Context, r *api.Repo) error { }).Tracef("deleting repo %s from the database", r.GetFullName()) // cast the library type to database type - repo := FromAPI(r) + repo := types.RepoFromAPI(r) // send query to the database return e.client. diff --git a/database/repo/delete_test.go b/database/repo/delete_test.go index 8829da36e..9326c62b6 100644 --- a/database/repo/delete_test.go +++ b/database/repo/delete_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestRepo_Engine_DeleteRepo(t *testing.T) { // setup types - _repo := testAPIRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetHash("baz") diff --git a/database/repo/get.go b/database/repo/get.go index ee603b09d..9d3fb7412 100644 --- a/database/repo/get.go +++ b/database/repo/get.go @@ -6,6 +6,7 @@ import ( "context" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -14,7 +15,7 @@ func (e *engine) GetRepo(ctx context.Context, id int64) (*api.Repo, error) { e.logger.Tracef("getting repo %d from the database", id) // variable to store query results - r := new(Repo) + r := new(types.Repo) // send query to the database and store result in variable err := e.client. @@ -45,15 +46,6 @@ func (e *engine) GetRepo(ctx context.Context, id int64) (*api.Repo, error) { return r.ToAPI(), nil } - // decrypt owner fields - err = r.Owner.Decrypt(e.config.EncryptionKey) - if err != nil { - e.logger.Errorf("unable to decrypt repo owner %d: %v", id, err) - - // return the unencrypted repo - return r.ToAPI(), nil - } - // return the decrypted repo // // https://pkg.go.dev/github.com/go-vela/types/database#Repo.ToLibrary diff --git a/database/repo/get_org.go b/database/repo/get_org.go index 889b5b812..ecca4530f 100644 --- a/database/repo/get_org.go +++ b/database/repo/get_org.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -19,7 +20,7 @@ func (e *engine) GetRepoForOrg(ctx context.Context, org, name string) (*api.Repo }).Tracef("getting repo %s/%s from the database", org, name) // variable to store query results - r := new(Repo) + r := new(types.Repo) // send query to the database and store result in variable err := e.client. @@ -47,15 +48,6 @@ func (e *engine) GetRepoForOrg(ctx context.Context, org, name string) (*api.Repo return r.ToAPI(), nil } - // decrypt owner fields - err = r.Owner.Decrypt(e.config.EncryptionKey) - if err != nil { - e.logger.Errorf("unable to decrypt repo owner %s/%s: %v", org, name, err) - - // return the unencrypted repo - return r.ToAPI(), nil - } - // return the decrypted repo return r.ToAPI(), nil } diff --git a/database/repo/get_org_test.go b/database/repo/get_org_test.go index 149b402a9..1570398c0 100644 --- a/database/repo/get_org_test.go +++ b/database/repo/get_org_test.go @@ -10,13 +10,14 @@ import ( "github.com/google/go-cmp/cmp" api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) func TestRepo_Engine_GetRepoForOrg(t *testing.T) { // setup types - _repo := testAPIRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.SetHash("baz") _repo.SetOrg("foo") @@ -27,7 +28,7 @@ func TestRepo_Engine_GetRepoForOrg(t *testing.T) { _repo.SetTopics([]string{}) _repo.SetAllowEvents(api.NewEventsFromMask(1)) - _owner := testOwner() + _owner := testutils.APIUser().Crop() _owner.SetID(1) _owner.SetName("foo") _owner.SetToken("bar") @@ -58,12 +59,12 @@ func TestRepo_Engine_GetRepoForOrg(t *testing.T) { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&user.User{}) + err = _sqlite.client.AutoMigrate(&types.User{}) if err != nil { t.Errorf("unable to create build table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableUser).Create(user.FromAPI(_owner)).Error + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error if err != nil { t.Errorf("unable to create test user for sqlite: %v", err) } diff --git a/database/repo/get_test.go b/database/repo/get_test.go index 651fc8f39..bab82c6f3 100644 --- a/database/repo/get_test.go +++ b/database/repo/get_test.go @@ -10,13 +10,14 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) func TestRepo_Engine_GetRepo(t *testing.T) { // setup types - _repo := testAPIRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.SetHash("baz") _repo.SetOrg("foo") @@ -27,7 +28,7 @@ func TestRepo_Engine_GetRepo(t *testing.T) { _repo.SetTopics([]string{}) _repo.SetAllowEvents(api.NewEventsFromMask(1)) - _owner := testOwner() + _owner := testutils.APIUser().Crop() _owner.SetID(1) _owner.SetName("foo") _owner.SetToken("bar") @@ -58,12 +59,12 @@ func TestRepo_Engine_GetRepo(t *testing.T) { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&user.User{}) + err = _sqlite.client.AutoMigrate(&types.User{}) if err != nil { t.Errorf("unable to create build table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableUser).Create(user.FromAPI(_owner)).Error + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error if err != nil { t.Errorf("unable to create test user for sqlite: %v", err) } diff --git a/database/repo/list.go b/database/repo/list.go index 2197acbb1..e50de9a21 100644 --- a/database/repo/list.go +++ b/database/repo/list.go @@ -6,6 +6,7 @@ import ( "context" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -15,7 +16,7 @@ func (e *engine) ListRepos(ctx context.Context) ([]*api.Repo, error) { // variables to store query results and return value count := int64(0) - r := new([]Repo) + r := new([]types.Repo) repos := []*api.Repo{} // count the results @@ -55,12 +56,6 @@ func (e *engine) ListRepos(ctx context.Context) ([]*api.Repo, error) { e.logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) } - // decrypt owner fields - err = tmp.Owner.Decrypt(e.config.EncryptionKey) - if err != nil { - e.logger.Errorf("unable to decrypt repo owner %d: %v", tmp.ID.Int64, err) - } - // convert query result to library type repos = append(repos, tmp.ToAPI()) } diff --git a/database/repo/list_org.go b/database/repo/list_org.go index 32529268e..bc1ee5597 100644 --- a/database/repo/list_org.go +++ b/database/repo/list_org.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -21,7 +22,7 @@ func (e *engine) ListReposForOrg(ctx context.Context, org, sortBy string, filter // variables to store query results and return values count := int64(0) - r := new([]Repo) + r := new([]types.Repo) repos := []*api.Repo{} // count the results @@ -94,12 +95,6 @@ func (e *engine) ListReposForOrg(ctx context.Context, org, sortBy string, filter e.logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) } - // decrypt owner fields - err = tmp.Owner.Decrypt(e.config.EncryptionKey) - if err != nil { - e.logger.Errorf("unable to decrypt repo owner %d: %v", tmp.ID.Int64, err) - } - // convert query result to API type repos = append(repos, tmp.ToAPI()) } diff --git a/database/repo/list_org_test.go b/database/repo/list_org_test.go index 7f13b540a..9a7bb5aa6 100644 --- a/database/repo/list_org_test.go +++ b/database/repo/list_org_test.go @@ -11,28 +11,21 @@ import ( "github.com/google/go-cmp/cmp" api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) func TestRepo_Engine_ListReposForOrg(t *testing.T) { // setup types - _buildOne := new(library.Build) - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetCreated(time.Now().UTC().Unix()) - - _buildTwo := new(library.Build) - _buildTwo.SetID(2) - _buildTwo.SetRepoID(2) - _buildTwo.SetNumber(1) - _buildTwo.SetCreated(time.Now().UTC().Unix()) + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") - _repoOne := testAPIRepo() + _repoOne := testutils.APIRepo() _repoOne.SetID(1) + _repoOne.SetOwner(_owner) _repoOne.SetHash("baz") _repoOne.SetOrg("foo") _repoOne.SetName("bar") @@ -42,8 +35,9 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { _repoOne.SetTopics([]string{}) _repoOne.SetAllowEvents(api.NewEventsFromMask(1)) - _repoTwo := testAPIRepo() + _repoTwo := testutils.APIRepo() _repoTwo.SetID(2) + _repoTwo.SetOwner(_owner) _repoTwo.SetHash("bar") _repoTwo.SetOrg("foo") _repoTwo.SetName("baz") @@ -53,13 +47,17 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { _repoTwo.SetTopics([]string{}) _repoTwo.SetAllowEvents(api.NewEventsFromMask(1)) - _owner := testOwner() - _owner.SetID(1) - _owner.SetName("foo") - _owner.SetToken("bar") + _buildOne := new(api.Build) + _buildOne.SetID(1) + _buildOne.SetRepo(_repoOne) + _buildOne.SetNumber(1) + _buildOne.SetCreated(time.Now().UTC().Unix()) - _repoOne.SetOwner(_owner) - _repoTwo.SetOwner(_owner) + _buildTwo := new(api.Build) + _buildTwo.SetID(2) + _buildTwo.SetRepo(_repoTwo) + _buildTwo.SetNumber(1) + _buildTwo.SetCreated(time.Now().UTC().Unix()) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -117,29 +115,29 @@ func TestRepo_Engine_ListReposForOrg(t *testing.T) { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&database.Build{}) + err = _sqlite.client.Migrator().CreateTable(&types.User{}) if err != nil { t.Errorf("unable to create build table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableBuild).Create(database.BuildFromLibrary(_buildOne).Crop()).Error + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error if err != nil { - t.Errorf("unable to create test build for sqlite: %v", err) + t.Errorf("unable to create test user for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableBuild).Create(database.BuildFromLibrary(_buildTwo).Crop()).Error + err = _sqlite.client.Migrator().CreateTable(&types.Build{}) if err != nil { - t.Errorf("unable to create test build for sqlite: %v", err) + t.Errorf("unable to create build table for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&user.User{}) + err = _sqlite.client.Table(constants.TableBuild).Create(types.BuildFromAPI(_buildOne)).Error if err != nil { - t.Errorf("unable to create build table for sqlite: %v", err) + t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableUser).Create(user.FromAPI(_owner)).Error + err = _sqlite.client.Table(constants.TableBuild).Create(types.BuildFromAPI(_buildTwo)).Error if err != nil { - t.Errorf("unable to create test user for sqlite: %v", err) + t.Errorf("unable to create test build for sqlite: %v", err) } // setup tests diff --git a/database/repo/list_test.go b/database/repo/list_test.go index 01df9981e..a4f40dcbe 100644 --- a/database/repo/list_test.go +++ b/database/repo/list_test.go @@ -10,14 +10,21 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) func TestRepo_Engine_ListRepos(t *testing.T) { // setup types - _repoOne := testAPIRepo() + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") + + _repoOne := testutils.APIRepo() _repoOne.SetID(1) + _repoOne.SetOwner(_owner) _repoOne.SetHash("baz") _repoOne.SetOrg("foo") _repoOne.SetName("bar") @@ -27,8 +34,9 @@ func TestRepo_Engine_ListRepos(t *testing.T) { _repoOne.SetTopics([]string{}) _repoOne.SetAllowEvents(api.NewEventsFromMask(1)) - _repoTwo := testAPIRepo() + _repoTwo := testutils.APIRepo() _repoTwo.SetID(2) + _repoTwo.SetOwner(_owner) _repoTwo.SetHash("baz") _repoTwo.SetOrg("bar") _repoTwo.SetName("foo") @@ -38,14 +46,6 @@ func TestRepo_Engine_ListRepos(t *testing.T) { _repoTwo.SetTopics([]string{}) _repoTwo.SetAllowEvents(api.NewEventsFromMask(1)) - _owner := testOwner() - _owner.SetID(1) - _owner.SetName("foo") - _owner.SetToken("bar") - - _repoOne.SetOwner(_owner) - _repoTwo.SetOwner(_owner) - _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -82,12 +82,12 @@ func TestRepo_Engine_ListRepos(t *testing.T) { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&user.User{}) + err = _sqlite.client.AutoMigrate(&types.User{}) if err != nil { t.Errorf("unable to create build table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableUser).Create(user.FromAPI(_owner)).Error + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error if err != nil { t.Errorf("unable to create test user for sqlite: %v", err) } diff --git a/database/repo/list_user.go b/database/repo/list_user.go index 1f1c709a1..37665769a 100644 --- a/database/repo/list_user.go +++ b/database/repo/list_user.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -21,7 +22,7 @@ func (e *engine) ListReposForUser(ctx context.Context, u *api.User, sortBy strin // variables to store query results and return values count := int64(0) - r := new([]Repo) + r := new([]types.Repo) repos := []*api.Repo{} // count the results @@ -94,12 +95,6 @@ func (e *engine) ListReposForUser(ctx context.Context, u *api.User, sortBy strin e.logger.Errorf("unable to decrypt repo %d: %v", tmp.ID.Int64, err) } - // decrypt owner fields - err = tmp.Owner.Decrypt(e.config.EncryptionKey) - if err != nil { - e.logger.Errorf("unable to decrypt repo owner %d: %v", tmp.ID.Int64, err) - } - // convert query result to library type repos = append(repos, tmp.ToAPI()) } diff --git a/database/repo/list_user_test.go b/database/repo/list_user_test.go index b89fce07e..49261c95e 100644 --- a/database/repo/list_user_test.go +++ b/database/repo/list_user_test.go @@ -11,29 +11,21 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/database/user" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/database" - "github.com/go-vela/types/library" ) func TestRepo_Engine_ListReposForUser(t *testing.T) { // setup types - _buildOne := new(library.Build) - _buildOne.SetID(1) - _buildOne.SetRepoID(1) - _buildOne.SetNumber(1) - _buildOne.SetCreated(time.Now().UTC().Unix()) - - _buildTwo := new(library.Build) - _buildTwo.SetID(2) - _buildTwo.SetRepoID(2) - _buildTwo.SetNumber(1) - _buildTwo.SetCreated(time.Now().UTC().Unix()) + _owner := testutils.APIUser().Crop() + _owner.SetID(1) + _owner.SetName("foo") + _owner.SetToken("bar") - _repoOne := testAPIRepo() + _repoOne := testutils.APIRepo() _repoOne.SetID(1) - _repoOne.GetOwner().SetID(1) + _repoOne.SetOwner(_owner) _repoOne.SetHash("baz") _repoOne.SetOrg("foo") _repoOne.SetName("bar") @@ -43,9 +35,9 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { _repoOne.SetTopics([]string{}) _repoOne.SetAllowEvents(api.NewEventsFromMask(1)) - _repoTwo := testAPIRepo() + _repoTwo := testutils.APIRepo() _repoTwo.SetID(2) - _repoTwo.GetOwner().SetID(1) + _repoTwo.SetOwner(_owner) _repoTwo.SetHash("baz") _repoTwo.SetOrg("bar") _repoTwo.SetName("foo") @@ -55,13 +47,17 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { _repoTwo.SetTopics([]string{}) _repoTwo.SetAllowEvents(api.NewEventsFromMask(1)) - _owner := testOwner() - _owner.SetID(1) - _owner.SetName("foo") - _owner.SetToken("bar") + _buildOne := new(api.Build) + _buildOne.SetID(1) + _buildOne.SetRepo(_repoOne) + _buildOne.SetNumber(1) + _buildOne.SetCreated(time.Now().UTC().Unix()) - _repoOne.SetOwner(_owner) - _repoTwo.SetOwner(_owner) + _buildTwo := new(api.Build) + _buildTwo.SetID(2) + _buildTwo.SetRepo(_repoTwo) + _buildTwo.SetNumber(1) + _buildTwo.SetCreated(time.Now().UTC().Unix()) _postgres, _mock := testPostgres(t) defer func() { _sql, _ := _postgres.client.DB(); _sql.Close() }() @@ -119,29 +115,29 @@ func TestRepo_Engine_ListReposForUser(t *testing.T) { t.Errorf("unable to create test repo for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&database.Build{}) + err = _sqlite.client.Migrator().CreateTable(&types.User{}) if err != nil { t.Errorf("unable to create build table for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableBuild).Create(database.BuildFromLibrary(_buildOne).Crop()).Error + err = _sqlite.client.Table(constants.TableUser).Create(types.UserFromAPI(_owner)).Error if err != nil { - t.Errorf("unable to create test build for sqlite: %v", err) + t.Errorf("unable to create test user for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableBuild).Create(database.BuildFromLibrary(_buildTwo).Crop()).Error + err = _sqlite.client.Migrator().CreateTable(&types.Build{}) if err != nil { - t.Errorf("unable to create test build for sqlite: %v", err) + t.Errorf("unable to create build table for sqlite: %v", err) } - err = _sqlite.client.AutoMigrate(&user.User{}) + err = _sqlite.client.Table(constants.TableBuild).Create(types.BuildFromAPI(_buildOne)).Error if err != nil { - t.Errorf("unable to create build table for sqlite: %v", err) + t.Errorf("unable to create test build for sqlite: %v", err) } - err = _sqlite.client.Table(constants.TableUser).Create(user.FromAPI(_owner)).Error + err = _sqlite.client.Table(constants.TableBuild).Create(types.BuildFromAPI(_buildTwo)).Error if err != nil { - t.Errorf("unable to create test user for sqlite: %v", err) + t.Errorf("unable to create test build for sqlite: %v", err) } // setup tests diff --git a/database/repo/repo.go b/database/repo/repo.go index fc1e7808e..6f9edeb19 100644 --- a/database/repo/repo.go +++ b/database/repo/repo.go @@ -4,51 +4,14 @@ package repo import ( "context" - "database/sql" - "encoding/base64" - "errors" "fmt" - "github.com/lib/pq" "github.com/sirupsen/logrus" "gorm.io/gorm" - api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/database/user" - "github.com/go-vela/server/util" "github.com/go-vela/types/constants" ) -var ( - // ErrEmptyRepoFullName defines the error type when a - // Repo type has an empty FullName field provided. - ErrEmptyRepoFullName = errors.New("empty repo full_name provided") - - // ErrEmptyRepoHash defines the error type when a - // Repo type has an empty Hash field provided. - ErrEmptyRepoHash = errors.New("empty repo hash provided") - - // ErrEmptyRepoName defines the error type when a - // Repo type has an empty Name field provided. - ErrEmptyRepoName = errors.New("empty repo name provided") - - // ErrEmptyRepoOrg defines the error type when a - // Repo type has an empty Org field provided. - ErrEmptyRepoOrg = errors.New("empty repo org provided") - - // ErrEmptyRepoUserID defines the error type when a - // Repo type has an empty UserID field provided. - ErrEmptyRepoUserID = errors.New("empty repo user_id provided") - - // ErrEmptyRepoVisibility defines the error type when a - // Repo type has an empty Visibility field provided. - ErrEmptyRepoVisibility = errors.New("empty repo visibility provided") - - // ErrExceededTopicsLimit defines the error type when a - // Repo type has Topics field provided that exceeds the database limit. - ErrExceededTopicsLimit = errors.New("exceeded topics limit") -) - type ( // config represents the settings required to create the engine that implements the RepoInterface interface. config struct { @@ -75,33 +38,6 @@ type ( // https://pkg.go.dev/github.com/sirupsen/logrus#Entry logger *logrus.Entry } - - // Repo is the database representation of a repo. - Repo struct { - ID sql.NullInt64 `sql:"id"` - UserID sql.NullInt64 `sql:"user_id"` - Hash sql.NullString `sql:"hash"` - Org sql.NullString `sql:"org"` - Name sql.NullString `sql:"name"` - FullName sql.NullString `sql:"full_name"` - Link sql.NullString `sql:"link"` - Clone sql.NullString `sql:"clone"` - Branch sql.NullString `sql:"branch"` - Topics pq.StringArray `sql:"topics" gorm:"type:varchar(1020)"` - BuildLimit sql.NullInt64 `sql:"build_limit"` - Timeout sql.NullInt64 `sql:"timeout"` - Counter sql.NullInt32 `sql:"counter"` - Visibility sql.NullString `sql:"visibility"` - Private sql.NullBool `sql:"private"` - Trusted sql.NullBool `sql:"trusted"` - Active sql.NullBool `sql:"active"` - AllowEvents sql.NullInt64 `sql:"allow_events"` - PipelineType sql.NullString `sql:"pipeline_type"` - PreviousName sql.NullString `sql:"previous_name"` - ApproveBuild sql.NullString `sql:"approve_build"` - - Owner user.User `gorm:"foreignKey:UserID"` - } ) // New creates and returns a Vela service for integrating with repos in the database. @@ -145,267 +81,3 @@ func New(opts ...EngineOpt) (*engine, error) { return e, nil } - -// Decrypt will manipulate the existing repo hash by -// base64 decoding that value. Then, a AES-256 cipher -// block is created from the encryption key in order to -// decrypt the base64 decoded secret value. -func (r *Repo) Decrypt(key string) error { - // base64 decode the encrypted repo hash - decoded, err := base64.StdEncoding.DecodeString(r.Hash.String) - if err != nil { - return err - } - - // decrypt the base64 decoded repo hash - decrypted, err := util.Decrypt(key, decoded) - if err != nil { - return err - } - - // set the decrypted repo hash - r.Hash = sql.NullString{ - String: string(decrypted), - Valid: true, - } - - return nil -} - -// Encrypt will manipulate the existing repo hash by -// creating a AES-256 cipher block from the encryption -// key in order to encrypt the repo hash. Then, the -// repo hash is base64 encoded for transport across -// network boundaries. -func (r *Repo) Encrypt(key string) error { - // encrypt the repo hash - encrypted, err := util.Encrypt(key, []byte(r.Hash.String)) - if err != nil { - return err - } - - // base64 encode the encrypted repo hash to make it network safe - r.Hash = sql.NullString{ - String: base64.StdEncoding.EncodeToString(encrypted), - Valid: true, - } - - return nil -} - -// Nullify ensures the valid flag for -// the sql.Null types are properly set. -// -// When a field within the Repo type is the zero -// value for the field, the valid flag is set to -// false causing it to be NULL in the database. -func (r *Repo) Nullify() *Repo { - if r == nil { - return nil - } - - // check if the ID field should be false - if r.ID.Int64 == 0 { - r.ID.Valid = false - } - - // check if the UserID field should be false - if r.UserID.Int64 == 0 { - r.UserID.Valid = false - } - - // check if the Hash field should be false - if len(r.Hash.String) == 0 { - r.Hash.Valid = false - } - - // check if the Org field should be false - if len(r.Org.String) == 0 { - r.Org.Valid = false - } - - // check if the Name field should be false - if len(r.Name.String) == 0 { - r.Name.Valid = false - } - - // check if the FullName field should be false - if len(r.FullName.String) == 0 { - r.FullName.Valid = false - } - - // check if the Link field should be false - if len(r.Link.String) == 0 { - r.Link.Valid = false - } - - // check if the Clone field should be false - if len(r.Clone.String) == 0 { - r.Clone.Valid = false - } - - // check if the Branch field should be false - if len(r.Branch.String) == 0 { - r.Branch.Valid = false - } - - // check if the BuildLimit field should be false - if r.BuildLimit.Int64 == 0 { - r.BuildLimit.Valid = false - } - - // check if the Timeout field should be false - if r.Timeout.Int64 == 0 { - r.Timeout.Valid = false - } - - // check if the AllowEvents field should be false - if r.AllowEvents.Int64 == 0 { - r.AllowEvents.Valid = false - } - - // check if the Visibility field should be false - if len(r.Visibility.String) == 0 { - r.Visibility.Valid = false - } - - // check if the PipelineType field should be false - if len(r.PipelineType.String) == 0 { - r.PipelineType.Valid = false - } - - // check if the PreviousName field should be false - if len(r.PreviousName.String) == 0 { - r.PreviousName.Valid = false - } - - // check if the ApproveForkBuild field should be false - if len(r.ApproveBuild.String) == 0 { - r.ApproveBuild.Valid = false - } - - return r -} - -// ToAPI converts the Repo type -// to an API Repo type. -func (r *Repo) ToAPI() *api.Repo { - repo := new(api.Repo) - - repo.SetID(r.ID.Int64) - repo.SetOwner(r.Owner.ToAPI().Crop()) - repo.SetHash(r.Hash.String) - repo.SetOrg(r.Org.String) - repo.SetName(r.Name.String) - repo.SetFullName(r.FullName.String) - repo.SetLink(r.Link.String) - repo.SetClone(r.Clone.String) - repo.SetBranch(r.Branch.String) - repo.SetTopics(r.Topics) - repo.SetBuildLimit(r.BuildLimit.Int64) - repo.SetTimeout(r.Timeout.Int64) - repo.SetCounter(int(r.Counter.Int32)) - repo.SetVisibility(r.Visibility.String) - repo.SetPrivate(r.Private.Bool) - repo.SetTrusted(r.Trusted.Bool) - repo.SetActive(r.Active.Bool) - repo.SetAllowEvents(api.NewEventsFromMask(r.AllowEvents.Int64)) - repo.SetPipelineType(r.PipelineType.String) - repo.SetPreviousName(r.PreviousName.String) - repo.SetApproveBuild(r.ApproveBuild.String) - - return repo -} - -// Validate verifies the necessary fields for -// the Repo type are populated correctly. -func (r *Repo) Validate() error { - // verify the UserID field is populated - if r.UserID.Int64 <= 0 { - return ErrEmptyRepoUserID - } - - // verify the Hash field is populated - if len(r.Hash.String) == 0 { - return ErrEmptyRepoHash - } - - // verify the Org field is populated - if len(r.Org.String) == 0 { - return ErrEmptyRepoOrg - } - - // verify the Name field is populated - if len(r.Name.String) == 0 { - return ErrEmptyRepoName - } - - // verify the FullName field is populated - if len(r.FullName.String) == 0 { - return ErrEmptyRepoFullName - } - - // verify the Visibility field is populated - if len(r.Visibility.String) == 0 { - return ErrEmptyRepoVisibility - } - - // calculate total size of favorites while sanitizing entries - total := 0 - - for i, t := range r.Topics { - r.Topics[i] = util.Sanitize(t) - total += len(t) - } - - // verify the Favorites field is within the database constraints - // len is to factor in number of comma separators included in the database field, - // removing 1 due to the last item not having an appended comma - if (total + len(r.Topics) - 1) > constants.TopicsMaxSize { - return ErrExceededTopicsLimit - } - - // ensure that all Repo string fields - // that can be returned as JSON are sanitized - // to avoid unsafe HTML content - r.Org = sql.NullString{String: util.Sanitize(r.Org.String), Valid: r.Org.Valid} - r.Name = sql.NullString{String: util.Sanitize(r.Name.String), Valid: r.Name.Valid} - r.FullName = sql.NullString{String: util.Sanitize(r.FullName.String), Valid: r.FullName.Valid} - r.Link = sql.NullString{String: util.Sanitize(r.Link.String), Valid: r.Link.Valid} - r.Clone = sql.NullString{String: util.Sanitize(r.Clone.String), Valid: r.Clone.Valid} - r.Branch = sql.NullString{String: util.Sanitize(r.Branch.String), Valid: r.Branch.Valid} - r.Visibility = sql.NullString{String: util.Sanitize(r.Visibility.String), Valid: r.Visibility.Valid} - r.PipelineType = sql.NullString{String: util.Sanitize(r.PipelineType.String), Valid: r.PipelineType.Valid} - - return nil -} - -// FromAPI converts the API Repo type -// to a database repo type. -func FromAPI(r *api.Repo) *Repo { - repo := &Repo{ - ID: sql.NullInt64{Int64: r.GetID(), Valid: true}, - UserID: sql.NullInt64{Int64: r.GetOwner().GetID(), Valid: true}, - Hash: sql.NullString{String: r.GetHash(), Valid: true}, - Org: sql.NullString{String: r.GetOrg(), Valid: true}, - Name: sql.NullString{String: r.GetName(), Valid: true}, - FullName: sql.NullString{String: r.GetFullName(), Valid: true}, - Link: sql.NullString{String: r.GetLink(), Valid: true}, - Clone: sql.NullString{String: r.GetClone(), Valid: true}, - Branch: sql.NullString{String: r.GetBranch(), Valid: true}, - Topics: pq.StringArray(r.GetTopics()), - BuildLimit: sql.NullInt64{Int64: r.GetBuildLimit(), Valid: true}, - Timeout: sql.NullInt64{Int64: r.GetTimeout(), Valid: true}, - Counter: sql.NullInt32{Int32: int32(r.GetCounter()), Valid: true}, - Visibility: sql.NullString{String: r.GetVisibility(), Valid: true}, - Private: sql.NullBool{Bool: r.GetPrivate(), Valid: true}, - Trusted: sql.NullBool{Bool: r.GetTrusted(), Valid: true}, - Active: sql.NullBool{Bool: r.GetActive(), Valid: true}, - AllowEvents: sql.NullInt64{Int64: r.GetAllowEvents().ToDatabase(), Valid: true}, - PipelineType: sql.NullString{String: r.GetPipelineType(), Valid: true}, - PreviousName: sql.NullString{String: r.GetPreviousName(), Valid: true}, - ApproveBuild: sql.NullString{String: r.GetApproveBuild(), Valid: true}, - } - - return repo.Nullify() -} diff --git a/database/repo/repo_test.go b/database/repo/repo_test.go index 8d50ade32..498940ebb 100644 --- a/database/repo/repo_test.go +++ b/database/repo/repo_test.go @@ -3,21 +3,15 @@ package repo import ( - "database/sql" "database/sql/driver" "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" - "github.com/google/go-cmp/cmp" "github.com/sirupsen/logrus" "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/api/types/actions" - "github.com/go-vela/types/constants" ) func TestRepo_New(t *testing.T) { @@ -155,7 +149,10 @@ func testPostgres(t *testing.T) (*engine, sqlmock.Sqlmock) { func testSqlite(t *testing.T) *engine { _sqlite, err := gorm.Open( sqlite.Open("file::memory:?cache=shared"), - &gorm.Config{SkipDefaultTransaction: true}, + &gorm.Config{ + SkipDefaultTransaction: true, + DisableForeignKeyConstraintWhenMigrating: true, + }, ) if err != nil { t.Errorf("unable to create new sqlite database: %v", err) @@ -174,73 +171,6 @@ func testSqlite(t *testing.T) *engine { return _engine } -// testAPIRepo is a test helper function to create an API -// Repo type with all fields set to their zero values. -func testAPIRepo() *api.Repo { - return &api.Repo{ - ID: new(int64), - Owner: testOwner(), - BuildLimit: new(int64), - Timeout: new(int64), - Counter: new(int), - PipelineType: new(string), - Hash: new(string), - Org: new(string), - Name: new(string), - FullName: new(string), - Link: new(string), - Clone: new(string), - Branch: new(string), - Visibility: new(string), - PreviousName: new(string), - ApproveBuild: new(string), - Private: new(bool), - Trusted: new(bool), - Active: new(bool), - AllowEvents: testEvents(), - } -} - -func testEvents() *api.Events { - return &api.Events{ - Push: &actions.Push{ - Branch: new(bool), - Tag: new(bool), - DeleteBranch: new(bool), - DeleteTag: new(bool), - }, - PullRequest: &actions.Pull{ - Opened: new(bool), - Edited: new(bool), - Synchronize: new(bool), - Reopened: new(bool), - Labeled: new(bool), - Unlabeled: new(bool), - }, - Deployment: &actions.Deploy{ - Created: new(bool), - }, - Comment: &actions.Comment{ - Created: new(bool), - Edited: new(bool), - }, - Schedule: &actions.Schedule{ - Run: new(bool), - }, - } -} - -// testOwner is a helper function that returns a sanitized user. -func testOwner() *api.User { - return &api.User{ - ID: new(int64), - Name: new(string), - RefreshToken: new(string), - Token: new(string), - Active: new(bool), - } -} - // This will be used with the github.com/DATA-DOG/go-sqlmock library to compare values // that are otherwise not easily compared. These typically would be values generated // before adding or updating them in the database. @@ -252,362 +182,3 @@ type AnyArgument struct{} func (a AnyArgument) Match(_ driver.Value) bool { return true } - -func TestRepo_Decrypt(t *testing.T) { - // setup types - key := "C639A572E14D5075C526FDDD43E4ECF6" - encrypted := testRepo() - - err := encrypted.Encrypt(key) - if err != nil { - t.Errorf("unable to encrypt repo: %v", err) - } - - // setup tests - tests := []struct { - failure bool - key string - repo Repo - }{ - { - failure: false, - key: key, - repo: *encrypted, - }, - { - failure: true, - key: "", - repo: *encrypted, - }, - { - failure: true, - key: key, - repo: *testRepo(), - }, - } - - // run tests - for _, test := range tests { - err := test.repo.Decrypt(test.key) - - if test.failure { - if err == nil { - t.Errorf("Decrypt should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Decrypt returned err: %v", err) - } - } -} - -func TestRepo_Encrypt(t *testing.T) { - // setup types - key := "C639A572E14D5075C526FDDD43E4ECF6" - - // setup tests - tests := []struct { - failure bool - key string - repo *Repo - }{ - { - failure: false, - key: key, - repo: testRepo(), - }, - { - failure: true, - key: "", - repo: testRepo(), - }, - } - - // run tests - for _, test := range tests { - err := test.repo.Encrypt(test.key) - - if test.failure { - if err == nil { - t.Errorf("Encrypt should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Encrypt returned err: %v", err) - } - } -} - -func TestRepo_Nullify(t *testing.T) { - // setup types - var r *Repo - - want := &Repo{ - ID: sql.NullInt64{Int64: 0, Valid: false}, - UserID: sql.NullInt64{Int64: 0, Valid: false}, - Hash: sql.NullString{String: "", Valid: false}, - Org: sql.NullString{String: "", Valid: false}, - Name: sql.NullString{String: "", Valid: false}, - FullName: sql.NullString{String: "", Valid: false}, - Link: sql.NullString{String: "", Valid: false}, - Clone: sql.NullString{String: "", Valid: false}, - Branch: sql.NullString{String: "", Valid: false}, - Timeout: sql.NullInt64{Int64: 0, Valid: false}, - AllowEvents: sql.NullInt64{Int64: 0, Valid: false}, - Visibility: sql.NullString{String: "", Valid: false}, - PipelineType: sql.NullString{String: "", Valid: false}, - ApproveBuild: sql.NullString{String: "", Valid: false}, - } - - // setup tests - tests := []struct { - repo *Repo - want *Repo - }{ - { - repo: testRepo(), - want: testRepo(), - }, - { - repo: r, - want: nil, - }, - { - repo: new(Repo), - want: want, - }, - } - - // run tests - for _, test := range tests { - got := test.repo.Nullify() - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("Nullify is %v, want %v", got, test.want) - } - } -} - -func TestRepo_ToAPI(t *testing.T) { - // setup types - want := new(api.Repo) - e := api.NewEventsFromMask(1) - owner := testOwner() - - want.SetID(1) - want.SetOwner(owner) - want.SetHash("superSecretHash") - want.SetOrg("github") - want.SetName("octocat") - want.SetFullName("github/octocat") - want.SetLink("https://github.com/github/octocat") - want.SetClone("https://github.com/github/octocat.git") - want.SetBranch("main") - want.SetTopics([]string{"cloud", "security"}) - want.SetBuildLimit(10) - want.SetTimeout(30) - want.SetCounter(0) - want.SetVisibility("public") - want.SetPrivate(false) - want.SetTrusted(false) - want.SetActive(true) - want.SetAllowEvents(e) - want.SetPipelineType("yaml") - want.SetPreviousName("oldName") - want.SetApproveBuild(constants.ApproveNever) - - // run test - got := testRepo().ToAPI() - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("ToAPI() mismatch (-want +got):\n%s", diff) - } -} - -func TestRepo_Validate(t *testing.T) { - // setup types - topics := []string{} - longTopic := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - - for len(topics) < 21 { - topics = append(topics, longTopic) - } - - // setup tests - tests := []struct { - failure bool - repo *Repo - }{ - { - failure: false, - repo: testRepo(), - }, - { // no user_id set for repo - failure: true, - repo: &Repo{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, - Org: sql.NullString{String: "github", Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - FullName: sql.NullString{String: "github/octocat", Valid: true}, - Visibility: sql.NullString{String: "public", Valid: true}, - }, - }, - { // no hash set for repo - failure: true, - repo: &Repo{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - UserID: sql.NullInt64{Int64: 1, Valid: true}, - Org: sql.NullString{String: "github", Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - FullName: sql.NullString{String: "github/octocat", Valid: true}, - Visibility: sql.NullString{String: "public", Valid: true}, - }, - }, - { // no org set for repo - failure: true, - repo: &Repo{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - UserID: sql.NullInt64{Int64: 1, Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - FullName: sql.NullString{String: "github/octocat", Valid: true}, - Visibility: sql.NullString{String: "public", Valid: true}, - }, - }, - { // no name set for repo - failure: true, - repo: &Repo{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - UserID: sql.NullInt64{Int64: 1, Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, - Org: sql.NullString{String: "github", Valid: true}, - FullName: sql.NullString{String: "github/octocat", Valid: true}, - Visibility: sql.NullString{String: "public", Valid: true}, - }, - }, - { // no full_name set for repo - failure: true, - repo: &Repo{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - UserID: sql.NullInt64{Int64: 1, Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, - Org: sql.NullString{String: "github", Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - Visibility: sql.NullString{String: "public", Valid: true}, - }, - }, - { // no visibility set for repo - failure: true, - repo: &Repo{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - UserID: sql.NullInt64{Int64: 1, Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, - Org: sql.NullString{String: "github", Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - FullName: sql.NullString{String: "github/octocat", Valid: true}, - }, - }, - { // topics exceed max size - failure: true, - repo: &Repo{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - UserID: sql.NullInt64{Int64: 1, Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, - Org: sql.NullString{String: "github", Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - FullName: sql.NullString{String: "github/octocat", Valid: true}, - Topics: topics, - }, - }, - } - - // run tests - for _, test := range tests { - err := test.repo.Validate() - - if test.failure { - if err == nil { - t.Errorf("Validate should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Validate returned err: %v", err) - } - } -} - -func TestRepo_FromAPI(t *testing.T) { - // setup types - r := new(api.Repo) - owner := testOwner() - owner.SetID(1) - - r.SetID(1) - r.SetOwner(owner) - r.SetHash("superSecretHash") - r.SetOrg("github") - r.SetName("octocat") - r.SetFullName("github/octocat") - r.SetLink("https://github.com/github/octocat") - r.SetClone("https://github.com/github/octocat.git") - r.SetBranch("main") - r.SetTopics([]string{"cloud", "security"}) - r.SetBuildLimit(10) - r.SetTimeout(30) - r.SetCounter(0) - r.SetVisibility("public") - r.SetPrivate(false) - r.SetTrusted(false) - r.SetActive(true) - r.SetAllowEvents(api.NewEventsFromMask(1)) - r.SetPipelineType("yaml") - r.SetPreviousName("oldName") - r.SetApproveBuild(constants.ApproveNever) - - want := testRepo() - - // run test - got := FromAPI(r) - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("FromAPI() mismatch (-want +got):\n%s", diff) - } -} - -// testRepo is a test helper function to create a Repo -// type with all fields set to a fake value. -func testRepo() *Repo { - return &Repo{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - UserID: sql.NullInt64{Int64: 1, Valid: true}, - Hash: sql.NullString{String: "superSecretHash", Valid: true}, - Org: sql.NullString{String: "github", Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - FullName: sql.NullString{String: "github/octocat", Valid: true}, - Link: sql.NullString{String: "https://github.com/github/octocat", Valid: true}, - Clone: sql.NullString{String: "https://github.com/github/octocat.git", Valid: true}, - Branch: sql.NullString{String: "main", Valid: true}, - Topics: []string{"cloud", "security"}, - BuildLimit: sql.NullInt64{Int64: 10, Valid: true}, - Timeout: sql.NullInt64{Int64: 30, Valid: true}, - Counter: sql.NullInt32{Int32: 0, Valid: true}, - Visibility: sql.NullString{String: "public", Valid: true}, - Private: sql.NullBool{Bool: false, Valid: true}, - Trusted: sql.NullBool{Bool: false, Valid: true}, - Active: sql.NullBool{Bool: true, Valid: true}, - AllowEvents: sql.NullInt64{Int64: 1, Valid: true}, - PipelineType: sql.NullString{String: "yaml", Valid: true}, - PreviousName: sql.NullString{String: "oldName", Valid: true}, - ApproveBuild: sql.NullString{String: constants.ApproveNever, Valid: true}, - } -} diff --git a/database/repo/update.go b/database/repo/update.go index 8bbcefbc9..31922068f 100644 --- a/database/repo/update.go +++ b/database/repo/update.go @@ -10,6 +10,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -21,7 +22,7 @@ func (e *engine) UpdateRepo(ctx context.Context, r *api.Repo) (*api.Repo, error) }).Tracef("creating repo %s in the database", r.GetFullName()) // cast the library type to database type - repo := FromAPI(r) + repo := types.RepoFromAPI(r) // validate the necessary fields are populated err := repo.Validate() @@ -46,8 +47,6 @@ func (e *engine) UpdateRepo(ctx context.Context, r *api.Repo) (*api.Repo, error) if err != nil { // only log to preserve backwards compatibility e.logger.Errorf("unable to decrypt repo %d: %v", r.GetID(), err) - - return repo.ToAPI(), nil } // set owner to provided owner if creation successful diff --git a/database/repo/update_test.go b/database/repo/update_test.go index 92e714567..e175a349a 100644 --- a/database/repo/update_test.go +++ b/database/repo/update_test.go @@ -10,12 +10,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/constants" ) func TestRepo_Engine_UpdateRepo(t *testing.T) { // setup types - _repo := testAPIRepo() + _repo := testutils.APIRepo() _repo.SetID(1) _repo.GetOwner().SetID(1) _repo.SetHash("baz") diff --git a/database/resource.go b/database/resource.go index d592179c8..cbdad190c 100644 --- a/database/resource.go +++ b/database/resource.go @@ -31,6 +31,7 @@ func (e *engine) NewResources(ctx context.Context) error { build.WithClient(e.client), build.WithLogger(e.logger), build.WithSkipCreation(e.config.SkipCreation), + build.WithEncryptionKey(e.config.EncryptionKey), ) if err != nil { return err diff --git a/database/service/clean_test.go b/database/service/clean_test.go index a3edada5b..b72d14dad 100644 --- a/database/service/clean_test.go +++ b/database/service/clean_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestService_Engine_CleanService(t *testing.T) { // setup types - _serviceOne := testService() + _serviceOne := testutils.APIService() _serviceOne.SetID(1) _serviceOne.SetRepoID(1) _serviceOne.SetBuildID(1) @@ -22,7 +24,7 @@ func TestService_Engine_CleanService(t *testing.T) { _serviceOne.SetCreated(1) _serviceOne.SetStatus("running") - _serviceTwo := testService() + _serviceTwo := testutils.APIService() _serviceTwo.SetID(2) _serviceTwo.SetRepoID(1) _serviceTwo.SetBuildID(1) @@ -32,7 +34,7 @@ func TestService_Engine_CleanService(t *testing.T) { _serviceTwo.SetCreated(1) _serviceTwo.SetStatus("pending") - _serviceThree := testService() + _serviceThree := testutils.APIService() _serviceThree.SetID(3) _serviceThree.SetRepoID(1) _serviceThree.SetBuildID(1) @@ -42,7 +44,7 @@ func TestService_Engine_CleanService(t *testing.T) { _serviceThree.SetCreated(1) _serviceThree.SetStatus("success") - _serviceFour := testService() + _serviceFour := testutils.APIService() _serviceFour.SetID(4) _serviceFour.SetRepoID(1) _serviceFour.SetBuildID(1) diff --git a/database/service/count_build.go b/database/service/count_build.go index f1d9f1e36..a15c061ff 100644 --- a/database/service/count_build.go +++ b/database/service/count_build.go @@ -7,12 +7,12 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) // CountServicesForBuild gets the count of services by build ID from the database. -func (e *engine) CountServicesForBuild(ctx context.Context, b *library.Build, filters map[string]interface{}) (int64, error) { +func (e *engine) CountServicesForBuild(ctx context.Context, b *api.Build, filters map[string]interface{}) (int64, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("getting count of services for build %d from the database", b.GetNumber()) diff --git a/database/service/count_build_test.go b/database/service/count_build_test.go index 09b013c0c..e0c1cefcf 100644 --- a/database/service/count_build_test.go +++ b/database/service/count_build_test.go @@ -8,16 +8,18 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestService_Engine_CountServicesForBuild(t *testing.T) { // setup types - _build := testBuild() + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(testutils.APIRepo()) _build.SetNumber(1) - _serviceOne := testService() + _serviceOne := testutils.APIService() _serviceOne.SetID(1) _serviceOne.SetRepoID(1) _serviceOne.SetBuildID(1) @@ -25,7 +27,7 @@ func TestService_Engine_CountServicesForBuild(t *testing.T) { _serviceOne.SetName("foo") _serviceOne.SetImage("bar") - _serviceTwo := testService() + _serviceTwo := testutils.APIService() _serviceTwo.SetID(2) _serviceTwo.SetRepoID(1) _serviceTwo.SetBuildID(2) diff --git a/database/service/count_test.go b/database/service/count_test.go index bbd0b6faf..c25a0d5b0 100644 --- a/database/service/count_test.go +++ b/database/service/count_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestService_Engine_CountServices(t *testing.T) { // setup types - _serviceOne := testService() + _serviceOne := testutils.APIService() _serviceOne.SetID(1) _serviceOne.SetRepoID(1) _serviceOne.SetBuildID(1) @@ -20,7 +22,7 @@ func TestService_Engine_CountServices(t *testing.T) { _serviceOne.SetName("foo") _serviceOne.SetImage("bar") - _serviceTwo := testService() + _serviceTwo := testutils.APIService() _serviceTwo.SetID(2) _serviceTwo.SetRepoID(1) _serviceTwo.SetBuildID(2) diff --git a/database/service/create_test.go b/database/service/create_test.go index b284bd4f8..6893daabc 100644 --- a/database/service/create_test.go +++ b/database/service/create_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestService_Engine_CreateService(t *testing.T) { // setup types - _service := testService() + _service := testutils.APIService() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) diff --git a/database/service/delete_test.go b/database/service/delete_test.go index 3600242d9..5481e9258 100644 --- a/database/service/delete_test.go +++ b/database/service/delete_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestService_Engine_DeleteService(t *testing.T) { // setup types - _service := testService() + _service := testutils.APIService() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) diff --git a/database/service/get_build.go b/database/service/get_build.go index cc4109762..26b5632c8 100644 --- a/database/service/get_build.go +++ b/database/service/get_build.go @@ -7,13 +7,14 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // GetServiceForBuild gets a service by number and build ID from the database. -func (e *engine) GetServiceForBuild(ctx context.Context, b *library.Build, number int) (*library.Service, error) { +func (e *engine) GetServiceForBuild(ctx context.Context, b *api.Build, number int) (*library.Service, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), "service": number, diff --git a/database/service/get_build_test.go b/database/service/get_build_test.go index af26ee7d0..da26e4ce9 100644 --- a/database/service/get_build_test.go +++ b/database/service/get_build_test.go @@ -9,17 +9,18 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestService_Engine_GetServiceForBuild(t *testing.T) { // setup types - _build := testBuild() + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(testutils.APIRepo()) _build.SetNumber(1) - _service := testService() + _service := testutils.APIService() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) diff --git a/database/service/get_test.go b/database/service/get_test.go index edeb82b9e..612811eed 100644 --- a/database/service/get_test.go +++ b/database/service/get_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestService_Engine_GetService(t *testing.T) { // setup types - _service := testService() + _service := testutils.APIService() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) diff --git a/database/service/interface.go b/database/service/interface.go index 90982afa0..40fc30293 100644 --- a/database/service/interface.go +++ b/database/service/interface.go @@ -5,6 +5,7 @@ package service import ( "context" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/library" ) @@ -29,7 +30,7 @@ type ServiceInterface interface { // CountServices defines a function that gets the count of all services. CountServices(context.Context) (int64, error) // CountServicesForBuild defines a function that gets the count of services by build ID. - CountServicesForBuild(context.Context, *library.Build, map[string]interface{}) (int64, error) + CountServicesForBuild(context.Context, *api.Build, map[string]interface{}) (int64, error) // CreateService defines a function that creates a new service. CreateService(context.Context, *library.Service) (*library.Service, error) // DeleteService defines a function that deletes an existing service. @@ -37,11 +38,11 @@ type ServiceInterface interface { // GetService defines a function that gets a service by ID. GetService(context.Context, int64) (*library.Service, error) // GetServiceForBuild defines a function that gets a service by number and build ID. - GetServiceForBuild(context.Context, *library.Build, int) (*library.Service, error) + GetServiceForBuild(context.Context, *api.Build, int) (*library.Service, error) // ListServices defines a function that gets a list of all services. ListServices(context.Context) ([]*library.Service, error) // ListServicesForBuild defines a function that gets a list of services by build ID. - ListServicesForBuild(context.Context, *library.Build, map[string]interface{}, int, int) ([]*library.Service, int64, error) + ListServicesForBuild(context.Context, *api.Build, map[string]interface{}, int, int) ([]*library.Service, int64, error) // ListServiceImageCount defines a function that gets a list of all service images and the count of their occurrence. ListServiceImageCount(context.Context) (map[string]float64, error) // ListServiceStatusCount defines a function that gets a list of all service statuses and the count of their occurrence. diff --git a/database/service/list_build.go b/database/service/list_build.go index 020f53fa0..98cb70294 100644 --- a/database/service/list_build.go +++ b/database/service/list_build.go @@ -7,13 +7,14 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // ListServicesForBuild gets a list of all services from the database. -func (e *engine) ListServicesForBuild(ctx context.Context, b *library.Build, filters map[string]interface{}, page int, perPage int) ([]*library.Service, int64, error) { +func (e *engine) ListServicesForBuild(ctx context.Context, b *api.Build, filters map[string]interface{}, page int, perPage int) ([]*library.Service, int64, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("listing services for build %d from the database", b.GetNumber()) diff --git a/database/service/list_build_test.go b/database/service/list_build_test.go index 283f7fe5b..cd09061ee 100644 --- a/database/service/list_build_test.go +++ b/database/service/list_build_test.go @@ -9,17 +9,18 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestService_Engine_ListServicesForBuild(t *testing.T) { // setup types - _build := testBuild() + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(testutils.APIRepo()) _build.SetNumber(1) - _serviceOne := testService() + _serviceOne := testutils.APIService() _serviceOne.SetID(1) _serviceOne.SetRepoID(1) _serviceOne.SetBuildID(1) @@ -27,7 +28,7 @@ func TestService_Engine_ListServicesForBuild(t *testing.T) { _serviceOne.SetName("foo") _serviceOne.SetImage("bar") - _serviceTwo := testService() + _serviceTwo := testutils.APIService() _serviceTwo.SetID(2) _serviceTwo.SetRepoID(1) _serviceTwo.SetBuildID(1) diff --git a/database/service/list_image_test.go b/database/service/list_image_test.go index fdf8a35fa..1bf4578b6 100644 --- a/database/service/list_image_test.go +++ b/database/service/list_image_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestService_Engine_ListServiceImageCount(t *testing.T) { // setup types - _serviceOne := testService() + _serviceOne := testutils.APIService() _serviceOne.SetID(1) _serviceOne.SetRepoID(1) _serviceOne.SetBuildID(1) @@ -20,7 +22,7 @@ func TestService_Engine_ListServiceImageCount(t *testing.T) { _serviceOne.SetName("foo") _serviceOne.SetImage("bar") - _serviceTwo := testService() + _serviceTwo := testutils.APIService() _serviceTwo.SetID(2) _serviceTwo.SetRepoID(1) _serviceTwo.SetBuildID(1) diff --git a/database/service/list_status_test.go b/database/service/list_status_test.go index 0b6e7ea1a..56b6f9203 100644 --- a/database/service/list_status_test.go +++ b/database/service/list_status_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestService_Engine_ListServiceStatusCount(t *testing.T) { // setup types - _serviceOne := testService() + _serviceOne := testutils.APIService() _serviceOne.SetID(1) _serviceOne.SetRepoID(1) _serviceOne.SetBuildID(1) @@ -20,7 +22,7 @@ func TestService_Engine_ListServiceStatusCount(t *testing.T) { _serviceOne.SetName("foo") _serviceOne.SetImage("bar") - _serviceTwo := testService() + _serviceTwo := testutils.APIService() _serviceTwo.SetID(2) _serviceTwo.SetRepoID(1) _serviceTwo.SetBuildID(1) diff --git a/database/service/list_test.go b/database/service/list_test.go index 6fcecdfd4..462dae56c 100644 --- a/database/service/list_test.go +++ b/database/service/list_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestService_Engine_ListServices(t *testing.T) { // setup types - _serviceOne := testService() + _serviceOne := testutils.APIService() _serviceOne.SetID(1) _serviceOne.SetRepoID(1) _serviceOne.SetBuildID(1) @@ -22,7 +23,7 @@ func TestService_Engine_ListServices(t *testing.T) { _serviceOne.SetName("foo") _serviceOne.SetImage("bar") - _serviceTwo := testService() + _serviceTwo := testutils.APIService() _serviceTwo.SetID(2) _serviceTwo.SetRepoID(1) _serviceTwo.SetBuildID(2) diff --git a/database/service/service_test.go b/database/service/service_test.go index 73a113568..9dcec640b 100644 --- a/database/service/service_test.go +++ b/database/service/service_test.go @@ -13,8 +13,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - "github.com/go-vela/types/library" ) func TestService_New(t *testing.T) { @@ -164,65 +162,6 @@ func testSqlite(t *testing.T) *engine { return _engine } -// testBuild is a test helper function to create a library -// Build type with all fields set to their zero values. -func testBuild() *library.Build { - return &library.Build{ - ID: new(int64), - RepoID: new(int64), - PipelineID: new(int64), - Number: new(int), - Parent: new(int), - Event: new(string), - EventAction: new(string), - Status: new(string), - Error: new(string), - Enqueued: new(int64), - Created: new(int64), - Started: new(int64), - Finished: new(int64), - Deploy: new(string), - Clone: new(string), - Source: new(string), - Title: new(string), - Message: new(string), - Commit: new(string), - Sender: new(string), - Author: new(string), - Email: new(string), - Link: new(string), - Branch: new(string), - Ref: new(string), - BaseRef: new(string), - HeadRef: new(string), - Host: new(string), - Runtime: new(string), - Distribution: new(string), - } -} - -// testService is a test helper function to create a library -// Service type with all fields set to their zero values. -func testService() *library.Service { - return &library.Service{ - ID: new(int64), - BuildID: new(int64), - RepoID: new(int64), - Number: new(int), - Name: new(string), - Image: new(string), - Status: new(string), - Error: new(string), - ExitCode: new(int), - Created: new(int64), - Started: new(int64), - Finished: new(int64), - Host: new(string), - Runtime: new(string), - Distribution: new(string), - } -} - // This will be used with the github.com/DATA-DOG/go-sqlmock library to compare values // that are otherwise not easily compared. These typically would be values generated // before adding or updating them in the database. diff --git a/database/service/update_test.go b/database/service/update_test.go index 6e8001deb..82dccac9c 100644 --- a/database/service/update_test.go +++ b/database/service/update_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestService_Engine_UpdateService(t *testing.T) { // setup types - _service := testService() + _service := testutils.APIService() _service.SetID(1) _service.SetRepoID(1) _service.SetBuildID(1) diff --git a/database/step/clean_test.go b/database/step/clean_test.go index a7cadded5..132d3a00d 100644 --- a/database/step/clean_test.go +++ b/database/step/clean_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestStep_Engine_CleanStep(t *testing.T) { // setup types - _stepOne := testStep() + _stepOne := testutils.APIStep() _stepOne.SetID(1) _stepOne.SetRepoID(1) _stepOne.SetBuildID(1) @@ -22,7 +24,7 @@ func TestStep_Engine_CleanStep(t *testing.T) { _stepOne.SetCreated(1) _stepOne.SetStatus("running") - _stepTwo := testStep() + _stepTwo := testutils.APIStep() _stepTwo.SetID(2) _stepTwo.SetRepoID(1) _stepTwo.SetBuildID(1) @@ -32,7 +34,7 @@ func TestStep_Engine_CleanStep(t *testing.T) { _stepTwo.SetCreated(1) _stepTwo.SetStatus("pending") - _stepThree := testStep() + _stepThree := testutils.APIStep() _stepThree.SetID(3) _stepThree.SetRepoID(1) _stepThree.SetBuildID(1) @@ -42,7 +44,7 @@ func TestStep_Engine_CleanStep(t *testing.T) { _stepThree.SetCreated(1) _stepThree.SetStatus("success") - _stepFour := testStep() + _stepFour := testutils.APIStep() _stepFour.SetID(4) _stepFour.SetRepoID(1) _stepFour.SetBuildID(1) diff --git a/database/step/count_build.go b/database/step/count_build.go index 595811112..35109fa06 100644 --- a/database/step/count_build.go +++ b/database/step/count_build.go @@ -7,12 +7,12 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) // CountStepsForBuild gets the count of steps by build ID from the database. -func (e *engine) CountStepsForBuild(ctx context.Context, b *library.Build, filters map[string]interface{}) (int64, error) { +func (e *engine) CountStepsForBuild(ctx context.Context, b *api.Build, filters map[string]interface{}) (int64, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("getting count of steps for build %d from the database", b.GetNumber()) diff --git a/database/step/count_build_test.go b/database/step/count_build_test.go index e17b666f3..dad4c0a59 100644 --- a/database/step/count_build_test.go +++ b/database/step/count_build_test.go @@ -8,16 +8,18 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestStep_Engine_CountStepsForBuild(t *testing.T) { // setup types - _build := testBuild() + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(testutils.APIRepo()) _build.SetNumber(1) - _stepOne := testStep() + _stepOne := testutils.APIStep() _stepOne.SetID(1) _stepOne.SetRepoID(1) _stepOne.SetBuildID(1) @@ -25,7 +27,7 @@ func TestStep_Engine_CountStepsForBuild(t *testing.T) { _stepOne.SetName("foo") _stepOne.SetImage("bar") - _stepTwo := testStep() + _stepTwo := testutils.APIStep() _stepTwo.SetID(2) _stepTwo.SetRepoID(1) _stepTwo.SetBuildID(2) diff --git a/database/step/count_test.go b/database/step/count_test.go index 621f0a7cd..bdc358a21 100644 --- a/database/step/count_test.go +++ b/database/step/count_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestStep_Engine_CountSteps(t *testing.T) { // setup types - _stepOne := testStep() + _stepOne := testutils.APIStep() _stepOne.SetID(1) _stepOne.SetRepoID(1) _stepOne.SetBuildID(1) @@ -20,7 +22,7 @@ func TestStep_Engine_CountSteps(t *testing.T) { _stepOne.SetName("foo") _stepOne.SetImage("bar") - _stepTwo := testStep() + _stepTwo := testutils.APIStep() _stepTwo.SetID(2) _stepTwo.SetRepoID(1) _stepTwo.SetBuildID(2) diff --git a/database/step/create_test.go b/database/step/create_test.go index 987ffb5b1..07824dc5a 100644 --- a/database/step/create_test.go +++ b/database/step/create_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestStep_Engine_CreateStep(t *testing.T) { // setup types - _step := testStep() + _step := testutils.APIStep() _step.SetID(1) _step.SetRepoID(1) _step.SetBuildID(1) diff --git a/database/step/delete_test.go b/database/step/delete_test.go index 476ee969f..25eae5a69 100644 --- a/database/step/delete_test.go +++ b/database/step/delete_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestStep_Engine_DeleteStep(t *testing.T) { // setup types - _step := testStep() + _step := testutils.APIStep() _step.SetID(1) _step.SetRepoID(1) _step.SetBuildID(1) diff --git a/database/step/get_build.go b/database/step/get_build.go index 99ed00026..9fd8a937e 100644 --- a/database/step/get_build.go +++ b/database/step/get_build.go @@ -7,13 +7,14 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // GetStepForBuild gets a step by number and build ID from the database. -func (e *engine) GetStepForBuild(ctx context.Context, b *library.Build, number int) (*library.Step, error) { +func (e *engine) GetStepForBuild(ctx context.Context, b *api.Build, number int) (*library.Step, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), "step": number, diff --git a/database/step/get_build_test.go b/database/step/get_build_test.go index 1906dc3f1..c5490aa58 100644 --- a/database/step/get_build_test.go +++ b/database/step/get_build_test.go @@ -9,17 +9,18 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/google/go-cmp/cmp" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestStep_Engine_GetStepForBuild(t *testing.T) { // setup types - _build := testBuild() + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(testutils.APIRepo()) _build.SetNumber(1) - _step := testStep() + _step := testutils.APIStep() _step.SetID(1) _step.SetRepoID(1) _step.SetBuildID(1) diff --git a/database/step/get_test.go b/database/step/get_test.go index a9e5106a1..4c05103ea 100644 --- a/database/step/get_test.go +++ b/database/step/get_test.go @@ -9,18 +9,20 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestStep_Engine_GetStep(t *testing.T) { // setup types - _step := testStep() + _step := testutils.APIStep() _step.SetID(1) _step.SetRepoID(1) _step.SetBuildID(1) _step.SetNumber(1) _step.SetName("foo") _step.SetImage("bar") + ctx := context.TODO() _postgres, _mock := testPostgres(t) diff --git a/database/step/interface.go b/database/step/interface.go index 3c41017a9..6de0cc168 100644 --- a/database/step/interface.go +++ b/database/step/interface.go @@ -5,6 +5,7 @@ package step import ( "context" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/library" ) @@ -29,7 +30,7 @@ type StepInterface interface { // CountSteps defines a function that gets the count of all steps. CountSteps(context.Context) (int64, error) // CountStepsForBuild defines a function that gets the count of steps by build ID. - CountStepsForBuild(context.Context, *library.Build, map[string]interface{}) (int64, error) + CountStepsForBuild(context.Context, *api.Build, map[string]interface{}) (int64, error) // CreateStep defines a function that creates a new step. CreateStep(context.Context, *library.Step) (*library.Step, error) // DeleteStep defines a function that deletes an existing step. @@ -37,11 +38,11 @@ type StepInterface interface { // GetStep defines a function that gets a step by ID. GetStep(context.Context, int64) (*library.Step, error) // GetStepForBuild defines a function that gets a step by number and build ID. - GetStepForBuild(context.Context, *library.Build, int) (*library.Step, error) + GetStepForBuild(context.Context, *api.Build, int) (*library.Step, error) // ListSteps defines a function that gets a list of all steps. ListSteps(ctx context.Context) ([]*library.Step, error) // ListStepsForBuild defines a function that gets a list of steps by build ID. - ListStepsForBuild(context.Context, *library.Build, map[string]interface{}, int, int) ([]*library.Step, int64, error) + ListStepsForBuild(context.Context, *api.Build, map[string]interface{}, int, int) ([]*library.Step, int64, error) // ListStepImageCount defines a function that gets a list of all step images and the count of their occurrence. ListStepImageCount(context.Context) (map[string]float64, error) // ListStepStatusCount defines a function that gets a list of all step statuses and the count of their occurrence. diff --git a/database/step/list_build.go b/database/step/list_build.go index dbf8a717a..fce2619e8 100644 --- a/database/step/list_build.go +++ b/database/step/list_build.go @@ -7,13 +7,14 @@ import ( "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" "github.com/go-vela/types/database" "github.com/go-vela/types/library" ) // ListStepsForBuild gets a list of all steps from the database. -func (e *engine) ListStepsForBuild(ctx context.Context, b *library.Build, filters map[string]interface{}, page int, perPage int) ([]*library.Step, int64, error) { +func (e *engine) ListStepsForBuild(ctx context.Context, b *api.Build, filters map[string]interface{}, page int, perPage int) ([]*library.Step, int64, error) { e.logger.WithFields(logrus.Fields{ "build": b.GetNumber(), }).Tracef("listing steps for build %d from the database", b.GetNumber()) diff --git a/database/step/list_build_test.go b/database/step/list_build_test.go index 46fda88a4..327076fec 100644 --- a/database/step/list_build_test.go +++ b/database/step/list_build_test.go @@ -9,17 +9,18 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestStep_Engine_ListStepsForBuild(t *testing.T) { // setup types - _build := testBuild() + _build := testutils.APIBuild() _build.SetID(1) - _build.SetRepoID(1) + _build.SetRepo(testutils.APIRepo()) _build.SetNumber(1) - _stepOne := testStep() + _stepOne := testutils.APIStep() _stepOne.SetID(1) _stepOne.SetRepoID(1) _stepOne.SetBuildID(1) @@ -27,7 +28,7 @@ func TestStep_Engine_ListStepsForBuild(t *testing.T) { _stepOne.SetName("foo") _stepOne.SetImage("bar") - _stepTwo := testStep() + _stepTwo := testutils.APIStep() _stepTwo.SetID(2) _stepTwo.SetRepoID(1) _stepTwo.SetBuildID(1) diff --git a/database/step/list_image_test.go b/database/step/list_image_test.go index ea0b78585..0447f9fc4 100644 --- a/database/step/list_image_test.go +++ b/database/step/list_image_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestStep_Engine_ListStepImageCount(t *testing.T) { // setup types - _stepOne := testStep() + _stepOne := testutils.APIStep() _stepOne.SetID(1) _stepOne.SetRepoID(1) _stepOne.SetBuildID(1) @@ -20,7 +22,7 @@ func TestStep_Engine_ListStepImageCount(t *testing.T) { _stepOne.SetName("foo") _stepOne.SetImage("bar") - _stepTwo := testStep() + _stepTwo := testutils.APIStep() _stepTwo.SetID(2) _stepTwo.SetRepoID(1) _stepTwo.SetBuildID(1) diff --git a/database/step/list_status_test.go b/database/step/list_status_test.go index 22f9d51c1..e6fa36ab4 100644 --- a/database/step/list_status_test.go +++ b/database/step/list_status_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestStep_Engine_ListStepStatusCount(t *testing.T) { // setup types - _stepOne := testStep() + _stepOne := testutils.APIStep() _stepOne.SetID(1) _stepOne.SetRepoID(1) _stepOne.SetBuildID(1) @@ -20,7 +22,7 @@ func TestStep_Engine_ListStepStatusCount(t *testing.T) { _stepOne.SetName("foo") _stepOne.SetImage("bar") - _stepTwo := testStep() + _stepTwo := testutils.APIStep() _stepTwo.SetID(2) _stepTwo.SetRepoID(1) _stepTwo.SetBuildID(1) diff --git a/database/step/list_test.go b/database/step/list_test.go index bed53585c..921a3f2f7 100644 --- a/database/step/list_test.go +++ b/database/step/list_test.go @@ -9,12 +9,13 @@ import ( "github.com/DATA-DOG/go-sqlmock" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/types/library" ) func TestStep_Engine_ListSteps(t *testing.T) { // setup types - _stepOne := testStep() + _stepOne := testutils.APIStep() _stepOne.SetID(1) _stepOne.SetRepoID(1) _stepOne.SetBuildID(1) @@ -22,7 +23,7 @@ func TestStep_Engine_ListSteps(t *testing.T) { _stepOne.SetName("foo") _stepOne.SetImage("bar") - _stepTwo := testStep() + _stepTwo := testutils.APIStep() _stepTwo.SetID(2) _stepTwo.SetRepoID(1) _stepTwo.SetBuildID(2) diff --git a/database/step/step_test.go b/database/step/step_test.go index 861937831..6643e5139 100644 --- a/database/step/step_test.go +++ b/database/step/step_test.go @@ -13,8 +13,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - "github.com/go-vela/types/library" ) func TestStep_New(t *testing.T) { @@ -164,67 +162,6 @@ func testSqlite(t *testing.T) *engine { return _engine } -// testBuild is a test helper function to create a library -// Build type with all fields set to their zero values. -func testBuild() *library.Build { - return &library.Build{ - ID: new(int64), - RepoID: new(int64), - PipelineID: new(int64), - Number: new(int), - Parent: new(int), - Event: new(string), - EventAction: new(string), - Status: new(string), - Error: new(string), - Enqueued: new(int64), - Created: new(int64), - Started: new(int64), - Finished: new(int64), - Deploy: new(string), - Clone: new(string), - Source: new(string), - Title: new(string), - Message: new(string), - Commit: new(string), - Sender: new(string), - Author: new(string), - Email: new(string), - Link: new(string), - Branch: new(string), - Ref: new(string), - BaseRef: new(string), - HeadRef: new(string), - Host: new(string), - Runtime: new(string), - Distribution: new(string), - } -} - -// testStep is a test helper function to create a library -// Step type with all fields set to their zero values. -func testStep() *library.Step { - return &library.Step{ - ID: new(int64), - BuildID: new(int64), - RepoID: new(int64), - Number: new(int), - Name: new(string), - Image: new(string), - Stage: new(string), - Status: new(string), - Error: new(string), - ExitCode: new(int), - Created: new(int64), - Started: new(int64), - Finished: new(int64), - Host: new(string), - Runtime: new(string), - Distribution: new(string), - ReportAs: new(string), - } -} - // This will be used with the github.com/DATA-DOG/go-sqlmock library to compare values // that are otherwise not easily compared. These typically would be values generated // before adding or updating them in the database. diff --git a/database/step/update_test.go b/database/step/update_test.go index d1b14dd2b..06a589307 100644 --- a/database/step/update_test.go +++ b/database/step/update_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestStep_Engine_UpdateStep(t *testing.T) { // setup types - _step := testStep() + _step := testutils.APIStep() _step.SetID(1) _step.SetRepoID(1) _step.SetBuildID(1) diff --git a/database/testutils/api_resources.go b/database/testutils/api_resources.go new file mode 100644 index 000000000..78aec3aa6 --- /dev/null +++ b/database/testutils/api_resources.go @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: Apache-2.0 + +package testutils + +import ( + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/api/types/actions" + "github.com/go-vela/types/library" + "github.com/go-vela/types/raw" +) + +// API TEST RESOURCES +// +// These are API resources initialized to their zero values for testing. + +func APIBuild() *api.Build { + return &api.Build{ + ID: new(int64), + Repo: APIRepo(), + PipelineID: new(int64), + Number: new(int), + Parent: new(int), + Event: new(string), + EventAction: new(string), + Status: new(string), + Error: new(string), + Enqueued: new(int64), + Created: new(int64), + Started: new(int64), + Finished: new(int64), + Deploy: new(string), + DeployNumber: new(int64), + Clone: new(string), + Source: new(string), + Title: new(string), + Message: new(string), + Commit: new(string), + Sender: new(string), + Author: new(string), + Email: new(string), + Link: new(string), + Branch: new(string), + Ref: new(string), + BaseRef: new(string), + HeadRef: new(string), + Host: new(string), + Runtime: new(string), + Distribution: new(string), + ApprovedAt: new(int64), + ApprovedBy: new(string), + } +} + +func APIDeployment() *library.Deployment { + builds := []*library.Build{} + + return &library.Deployment{ + ID: new(int64), + RepoID: new(int64), + Number: new(int64), + URL: new(string), + Commit: new(string), + Ref: new(string), + Task: new(string), + Target: new(string), + Description: new(string), + Payload: new(raw.StringSliceMap), + CreatedAt: new(int64), + CreatedBy: new(string), + Builds: builds, + } +} + +func APIEvents() *api.Events { + return &api.Events{ + Push: &actions.Push{ + Branch: new(bool), + Tag: new(bool), + DeleteBranch: new(bool), + DeleteTag: new(bool), + }, + PullRequest: &actions.Pull{ + Opened: new(bool), + Edited: new(bool), + Synchronize: new(bool), + Reopened: new(bool), + Labeled: new(bool), + Unlabeled: new(bool), + }, + Deployment: &actions.Deploy{ + Created: new(bool), + }, + Comment: &actions.Comment{ + Created: new(bool), + Edited: new(bool), + }, + Schedule: &actions.Schedule{ + Run: new(bool), + }, + } +} + +func APIRepo() *api.Repo { + return &api.Repo{ + ID: new(int64), + Owner: APIUser(), + BuildLimit: new(int64), + Timeout: new(int64), + Counter: new(int), + PipelineType: new(string), + Hash: new(string), + Org: new(string), + Name: new(string), + FullName: new(string), + Link: new(string), + Clone: new(string), + Branch: new(string), + Visibility: new(string), + PreviousName: new(string), + Private: new(bool), + Trusted: new(bool), + Active: new(bool), + AllowEvents: APIEvents(), + Topics: new([]string), + ApproveBuild: new(string), + } +} + +func APIUser() *api.User { + return &api.User{ + ID: new(int64), + Name: new(string), + RefreshToken: new(string), + Token: new(string), + Favorites: new([]string), + Dashboards: new([]string), + Active: new(bool), + Admin: new(bool), + } +} + +func APIHook() *library.Hook { + return &library.Hook{ + ID: new(int64), + RepoID: new(int64), + BuildID: new(int64), + Number: new(int), + SourceID: new(string), + Created: new(int64), + Host: new(string), + Event: new(string), + EventAction: new(string), + Branch: new(string), + Error: new(string), + Status: new(string), + Link: new(string), + WebhookID: new(int64), + } +} + +func APILog() *library.Log { + return &library.Log{ + ID: new(int64), + RepoID: new(int64), + BuildID: new(int64), + ServiceID: new(int64), + StepID: new(int64), + Data: new([]byte), + } +} + +func APIService() *library.Service { + return &library.Service{ + ID: new(int64), + BuildID: new(int64), + RepoID: new(int64), + Number: new(int), + Name: new(string), + Image: new(string), + Status: new(string), + Error: new(string), + ExitCode: new(int), + Created: new(int64), + Started: new(int64), + Finished: new(int64), + Host: new(string), + Runtime: new(string), + Distribution: new(string), + } +} + +func APIStep() *library.Step { + return &library.Step{ + ID: new(int64), + BuildID: new(int64), + RepoID: new(int64), + Number: new(int), + Name: new(string), + Image: new(string), + Stage: new(string), + Status: new(string), + Error: new(string), + ExitCode: new(int), + Created: new(int64), + Started: new(int64), + Finished: new(int64), + Host: new(string), + Runtime: new(string), + Distribution: new(string), + ReportAs: new(string), + } +} + +func APIPipeline() *library.Pipeline { + return &library.Pipeline{ + ID: new(int64), + RepoID: new(int64), + Commit: new(string), + Flavor: new(string), + Platform: new(string), + Ref: new(string), + Type: new(string), + Version: new(string), + ExternalSecrets: new(bool), + InternalSecrets: new(bool), + Services: new(bool), + Stages: new(bool), + Steps: new(bool), + Templates: new(bool), + Data: new([]byte), + } +} + +func APIDashboard() *api.Dashboard { + return &api.Dashboard{ + ID: new(string), + Name: new(string), + CreatedAt: new(int64), + CreatedBy: new(string), + UpdatedAt: new(int64), + UpdatedBy: new(string), + Admins: &[]*api.User{APIUser()}, + Repos: &[]*api.DashboardRepo{APIDashboardRepo()}, + } +} + +func APIDashboardRepo() *api.DashboardRepo { + return &api.DashboardRepo{ + ID: new(int64), + Branches: new([]string), + Events: new([]string), + } +} diff --git a/database/types/build.go b/database/types/build.go new file mode 100644 index 000000000..4023836e6 --- /dev/null +++ b/database/types/build.go @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "errors" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/util" + "github.com/go-vela/types/raw" +) + +var ( + // ErrEmptyBuildNumber defines the error type when a + // Build type has an empty Number field provided. + ErrEmptyBuildNumber = errors.New("empty build number provided") + + // ErrEmptyBuildRepoID defines the error type when a + // Build type has an empty `RepoID` field provided. + ErrEmptyBuildRepoID = errors.New("empty build repo_id provided") +) + +const ( + // Maximum title field length. + maxTitleLength = 1000 + // Maximum message field length. + maxMessageLength = 2000 + // Maximum error field length. + maxErrorLength = 1000 +) + +// Build is the database representation of a build for a pipeline. +type Build struct { + ID sql.NullInt64 `sql:"id"` + RepoID sql.NullInt64 `sql:"repo_id"` + PipelineID sql.NullInt64 `sql:"pipeline_id"` + Number sql.NullInt32 `sql:"number"` + Parent sql.NullInt32 `sql:"parent"` + Event sql.NullString `sql:"event"` + EventAction sql.NullString `sql:"event_action"` + Status sql.NullString `sql:"status"` + Error sql.NullString `sql:"error"` + Enqueued sql.NullInt64 `sql:"enqueued"` + Created sql.NullInt64 `sql:"created"` + Started sql.NullInt64 `sql:"started"` + Finished sql.NullInt64 `sql:"finished"` + Deploy sql.NullString `sql:"deploy"` + DeployNumber sql.NullInt64 `sql:"deploy_number"` + DeployPayload raw.StringSliceMap `sql:"deploy_payload" gorm:"type:varchar(2000)"` + Clone sql.NullString `sql:"clone"` + Source sql.NullString `sql:"source"` + Title sql.NullString `sql:"title"` + Message sql.NullString `sql:"message"` + Commit sql.NullString `sql:"commit"` + Sender sql.NullString `sql:"sender"` + Author sql.NullString `sql:"author"` + Email sql.NullString `sql:"email"` + Link sql.NullString `sql:"link"` + Branch sql.NullString `sql:"branch"` + Ref sql.NullString `sql:"ref"` + BaseRef sql.NullString `sql:"base_ref"` + HeadRef sql.NullString `sql:"head_ref"` + Host sql.NullString `sql:"host"` + Runtime sql.NullString `sql:"runtime"` + Distribution sql.NullString `sql:"distribution"` + ApprovedAt sql.NullInt64 `sql:"approved_at"` + ApprovedBy sql.NullString `sql:"approved_by"` + + Repo Repo `gorm:"foreignKey:RepoID"` +} + +// Crop prepares the Build type for inserting into the database by +// trimming values that may exceed the database column limit. +func (b *Build) Crop() *Build { + // trim the Title field to 1000 characters + if len(b.Title.String) > maxTitleLength { + b.Title = sql.NullString{String: b.Title.String[:maxTitleLength], Valid: true} + } + + // trim the Message field to 2000 characters + if len(b.Message.String) > maxMessageLength { + b.Message = sql.NullString{String: b.Message.String[:maxMessageLength], Valid: true} + } + + // trim the Error field to 1000 characters + if len(b.Error.String) > maxErrorLength { + b.Error = sql.NullString{String: b.Error.String[:maxErrorLength], Valid: true} + } + + return b +} + +// Nullify ensures the valid flag for +// the sql.Null types are properly set. +// +// When a field within the Build type is the zero +// value for the field, the valid flag is set to +// false causing it to be NULL in the database. +// +//nolint:gocyclo,funlen // ignore cyclomatic complexity due to number of fields +func (b *Build) Nullify() *Build { + if b == nil { + return nil + } + + // check if the ID field should be false + if b.ID.Int64 == 0 { + b.ID.Valid = false + } + + // check if the RepoID field should be false + if b.RepoID.Int64 == 0 { + b.RepoID.Valid = false + } + + // check if the PipelineID field should be false + if b.PipelineID.Int64 == 0 { + b.PipelineID.Valid = false + } + + // check if the Number field should be false + if b.Number.Int32 == 0 { + b.Number.Valid = false + } + + // check if the Parent field should be false + if b.Parent.Int32 == 0 { + b.Parent.Valid = false + } + + // check if the Event field should be false + if len(b.Event.String) == 0 { + b.Event.Valid = false + } + + // check if the EventAction field should be false + if len(b.EventAction.String) == 0 { + b.EventAction.Valid = false + } + + // check if the Status field should be false + if len(b.Status.String) == 0 { + b.Status.Valid = false + } + + // check if the Error field should be false + if len(b.Error.String) == 0 { + b.Error.Valid = false + } + + // check if the Enqueued field should be false + if b.Enqueued.Int64 == 0 { + b.Enqueued.Valid = false + } + + // check if the Created field should be false + if b.Created.Int64 == 0 { + b.Created.Valid = false + } + + // check if the Started field should be false + if b.Started.Int64 == 0 { + b.Started.Valid = false + } + + // check if the Finished field should be false + if b.Finished.Int64 == 0 { + b.Finished.Valid = false + } + + // check if the Deploy field should be false + if len(b.Deploy.String) == 0 { + b.Deploy.Valid = false + } + + // check if the DeployNumber field should be false + if b.DeployNumber.Int64 == 0 { + b.DeployNumber.Valid = false + } + + // check if the Clone field should be false + if len(b.Clone.String) == 0 { + b.Clone.Valid = false + } + + // check if the Source field should be false + if len(b.Source.String) == 0 { + b.Source.Valid = false + } + + // check if the Title field should be false + if len(b.Title.String) == 0 { + b.Title.Valid = false + } + + // check if the Message field should be false + if len(b.Message.String) == 0 { + b.Message.Valid = false + } + + // check if the Commit field should be false + if len(b.Commit.String) == 0 { + b.Commit.Valid = false + } + + // check if the Sender field should be false + if len(b.Sender.String) == 0 { + b.Sender.Valid = false + } + + // check if the Author field should be false + if len(b.Author.String) == 0 { + b.Author.Valid = false + } + + // check if the Email field should be false + if len(b.Email.String) == 0 { + b.Email.Valid = false + } + + // check if the Link field should be false + if len(b.Link.String) == 0 { + b.Link.Valid = false + } + + // check if the Branch field should be false + if len(b.Branch.String) == 0 { + b.Branch.Valid = false + } + + // check if the Ref field should be false + if len(b.Ref.String) == 0 { + b.Ref.Valid = false + } + + // check if the BaseRef field should be false + if len(b.BaseRef.String) == 0 { + b.BaseRef.Valid = false + } + + // check if the HeadRef field should be false + if len(b.HeadRef.String) == 0 { + b.HeadRef.Valid = false + } + + // check if the Host field should be false + if len(b.Host.String) == 0 { + b.Host.Valid = false + } + + // check if the Runtime field should be false + if len(b.Runtime.String) == 0 { + b.Runtime.Valid = false + } + + // check if the Distribution field should be false + if len(b.Distribution.String) == 0 { + b.Distribution.Valid = false + } + + // check if the ApprovedAt field should be false + if b.ApprovedAt.Int64 == 0 { + b.ApprovedAt.Valid = false + } + + // check if the ApprovedBy field should be false + if len(b.ApprovedBy.String) == 0 { + b.ApprovedBy.Valid = false + } + + return b +} + +// ToAPI converts the Build type +// to an API Build type. +func (b *Build) ToAPI() *api.Build { + build := new(api.Build) + + build.SetID(b.ID.Int64) + build.SetRepo(b.Repo.ToAPI()) + build.SetPipelineID(b.PipelineID.Int64) + build.SetNumber(int(b.Number.Int32)) + build.SetParent(int(b.Parent.Int32)) + build.SetEvent(b.Event.String) + build.SetEventAction(b.EventAction.String) + build.SetStatus(b.Status.String) + build.SetError(b.Error.String) + build.SetEnqueued(b.Enqueued.Int64) + build.SetCreated(b.Created.Int64) + build.SetStarted(b.Started.Int64) + build.SetFinished(b.Finished.Int64) + build.SetDeploy(b.Deploy.String) + build.SetDeployNumber(b.DeployNumber.Int64) + build.SetDeployPayload(b.DeployPayload) + build.SetClone(b.Clone.String) + build.SetSource(b.Source.String) + build.SetTitle(b.Title.String) + build.SetMessage(b.Message.String) + build.SetCommit(b.Commit.String) + build.SetSender(b.Sender.String) + build.SetAuthor(b.Author.String) + build.SetEmail(b.Email.String) + build.SetLink(b.Link.String) + build.SetBranch(b.Branch.String) + build.SetRef(b.Ref.String) + build.SetBaseRef(b.BaseRef.String) + build.SetHeadRef(b.HeadRef.String) + build.SetHost(b.Host.String) + build.SetRuntime(b.Runtime.String) + build.SetDistribution(b.Distribution.String) + build.SetApprovedAt(b.ApprovedAt.Int64) + build.SetApprovedBy(b.ApprovedBy.String) + + return build +} + +// Validate verifies the necessary fields for +// the Build type are populated correctly. +func (b *Build) Validate() error { + // verify the RepoID field is populated + if b.RepoID.Int64 <= 0 { + return ErrEmptyBuildRepoID + } + + // verify the Number field is populated + if b.Number.Int32 <= 0 { + return ErrEmptyBuildNumber + } + + // ensure that all Build string fields + // that can be returned as JSON are sanitized + // to avoid unsafe HTML content + b.Event = sql.NullString{String: util.Sanitize(b.Event.String), Valid: b.Event.Valid} + b.EventAction = sql.NullString{String: util.Sanitize(b.EventAction.String), Valid: b.EventAction.Valid} + b.Status = sql.NullString{String: util.Sanitize(b.Status.String), Valid: b.Status.Valid} + b.Error = sql.NullString{String: util.Sanitize(b.Error.String), Valid: b.Error.Valid} + b.Deploy = sql.NullString{String: util.Sanitize(b.Deploy.String), Valid: b.Deploy.Valid} + b.Clone = sql.NullString{String: util.Sanitize(b.Clone.String), Valid: b.Clone.Valid} + b.Source = sql.NullString{String: util.Sanitize(b.Source.String), Valid: b.Source.Valid} + b.Title = sql.NullString{String: util.Sanitize(b.Title.String), Valid: b.Title.Valid} + b.Message = sql.NullString{String: util.Sanitize(b.Message.String), Valid: b.Message.Valid} + b.Commit = sql.NullString{String: util.Sanitize(b.Commit.String), Valid: b.Commit.Valid} + b.Sender = sql.NullString{String: util.Sanitize(b.Sender.String), Valid: b.Sender.Valid} + b.Author = sql.NullString{String: util.Sanitize(b.Author.String), Valid: b.Author.Valid} + b.Email = sql.NullString{String: util.Sanitize(b.Email.String), Valid: b.Email.Valid} + b.Link = sql.NullString{String: util.Sanitize(b.Link.String), Valid: b.Link.Valid} + b.Branch = sql.NullString{String: util.Sanitize(b.Branch.String), Valid: b.Branch.Valid} + b.Ref = sql.NullString{String: util.Sanitize(b.Ref.String), Valid: b.Ref.Valid} + b.BaseRef = sql.NullString{String: util.Sanitize(b.BaseRef.String), Valid: b.BaseRef.Valid} + b.HeadRef = sql.NullString{String: util.Sanitize(b.HeadRef.String), Valid: b.HeadRef.Valid} + b.Host = sql.NullString{String: util.Sanitize(b.Host.String), Valid: b.Host.Valid} + b.Runtime = sql.NullString{String: util.Sanitize(b.Runtime.String), Valid: b.Runtime.Valid} + b.Distribution = sql.NullString{String: util.Sanitize(b.Distribution.String), Valid: b.Distribution.Valid} + b.ApprovedBy = sql.NullString{String: util.Sanitize(b.ApprovedBy.String), Valid: b.ApprovedBy.Valid} + + return nil +} + +// BuildFromAPI converts the API Build type +// to a database build type. +func BuildFromAPI(b *api.Build) *Build { + build := &Build{ + ID: sql.NullInt64{Int64: b.GetID(), Valid: true}, + RepoID: sql.NullInt64{Int64: b.GetRepo().GetID(), Valid: true}, + PipelineID: sql.NullInt64{Int64: b.GetPipelineID(), Valid: true}, + Number: sql.NullInt32{Int32: int32(b.GetNumber()), Valid: true}, + Parent: sql.NullInt32{Int32: int32(b.GetParent()), Valid: true}, + Event: sql.NullString{String: b.GetEvent(), Valid: true}, + EventAction: sql.NullString{String: b.GetEventAction(), Valid: true}, + Status: sql.NullString{String: b.GetStatus(), Valid: true}, + Error: sql.NullString{String: b.GetError(), Valid: true}, + Enqueued: sql.NullInt64{Int64: b.GetEnqueued(), Valid: true}, + Created: sql.NullInt64{Int64: b.GetCreated(), Valid: true}, + Started: sql.NullInt64{Int64: b.GetStarted(), Valid: true}, + Finished: sql.NullInt64{Int64: b.GetFinished(), Valid: true}, + Deploy: sql.NullString{String: b.GetDeploy(), Valid: true}, + DeployNumber: sql.NullInt64{Int64: b.GetDeployNumber(), Valid: true}, + DeployPayload: b.GetDeployPayload(), + Clone: sql.NullString{String: b.GetClone(), Valid: true}, + Source: sql.NullString{String: b.GetSource(), Valid: true}, + Title: sql.NullString{String: b.GetTitle(), Valid: true}, + Message: sql.NullString{String: b.GetMessage(), Valid: true}, + Commit: sql.NullString{String: b.GetCommit(), Valid: true}, + Sender: sql.NullString{String: b.GetSender(), Valid: true}, + Author: sql.NullString{String: b.GetAuthor(), Valid: true}, + Email: sql.NullString{String: b.GetEmail(), Valid: true}, + Link: sql.NullString{String: b.GetLink(), Valid: true}, + Branch: sql.NullString{String: b.GetBranch(), Valid: true}, + Ref: sql.NullString{String: b.GetRef(), Valid: true}, + BaseRef: sql.NullString{String: b.GetBaseRef(), Valid: true}, + HeadRef: sql.NullString{String: b.GetHeadRef(), Valid: true}, + Host: sql.NullString{String: b.GetHost(), Valid: true}, + Runtime: sql.NullString{String: b.GetRuntime(), Valid: true}, + Distribution: sql.NullString{String: b.GetDistribution(), Valid: true}, + ApprovedAt: sql.NullInt64{Int64: b.GetApprovedAt(), Valid: true}, + ApprovedBy: sql.NullString{String: b.GetApprovedBy(), Valid: true}, + } + + return build.Nullify() +} diff --git a/database/types/build_test.go b/database/types/build_test.go new file mode 100644 index 000000000..04a88d923 --- /dev/null +++ b/database/types/build_test.go @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "math/rand" + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/types/raw" +) + +func TestTypes_Build_Crop(t *testing.T) { + // setup types + title := randomString(1001) + message := randomString(2001) + err := randomString(1001) + + b := testBuild() + b.Title = sql.NullString{String: title, Valid: true} + b.Message = sql.NullString{String: message, Valid: true} + b.Error = sql.NullString{String: err, Valid: true} + + want := testBuild() + want.Title = sql.NullString{String: title[:1000], Valid: true} + want.Message = sql.NullString{String: message[:2000], Valid: true} + want.Error = sql.NullString{String: err[:1000], Valid: true} + + // run test + got := b.Crop() + + if !reflect.DeepEqual(got, want) { + t.Errorf("Crop is %v, want %v", got, want) + } +} + +func TestTypes_Build_Nullify(t *testing.T) { + // setup types + var b *Build + + want := &Build{ + ID: sql.NullInt64{Int64: 0, Valid: false}, + RepoID: sql.NullInt64{Int64: 0, Valid: false}, + PipelineID: sql.NullInt64{Int64: 0, Valid: false}, + Number: sql.NullInt32{Int32: 0, Valid: false}, + Parent: sql.NullInt32{Int32: 0, Valid: false}, + Event: sql.NullString{String: "", Valid: false}, + EventAction: sql.NullString{String: "", Valid: false}, + Status: sql.NullString{String: "", Valid: false}, + Error: sql.NullString{String: "", Valid: false}, + Enqueued: sql.NullInt64{Int64: 0, Valid: false}, + Created: sql.NullInt64{Int64: 0, Valid: false}, + Started: sql.NullInt64{Int64: 0, Valid: false}, + Finished: sql.NullInt64{Int64: 0, Valid: false}, + Deploy: sql.NullString{String: "", Valid: false}, + DeployNumber: sql.NullInt64{Int64: 0, Valid: false}, + DeployPayload: nil, + Clone: sql.NullString{String: "", Valid: false}, + Source: sql.NullString{String: "", Valid: false}, + Title: sql.NullString{String: "", Valid: false}, + Message: sql.NullString{String: "", Valid: false}, + Commit: sql.NullString{String: "", Valid: false}, + Sender: sql.NullString{String: "", Valid: false}, + Author: sql.NullString{String: "", Valid: false}, + Email: sql.NullString{String: "", Valid: false}, + Link: sql.NullString{String: "", Valid: false}, + Branch: sql.NullString{String: "", Valid: false}, + Ref: sql.NullString{String: "", Valid: false}, + BaseRef: sql.NullString{String: "", Valid: false}, + HeadRef: sql.NullString{String: "", Valid: false}, + Host: sql.NullString{String: "", Valid: false}, + Runtime: sql.NullString{String: "", Valid: false}, + Distribution: sql.NullString{String: "", Valid: false}, + } + + // setup tests + tests := []struct { + build *Build + want *Build + }{ + { + build: testBuild(), + want: testBuild(), + }, + { + build: b, + want: nil, + }, + { + build: new(Build), + want: want, + }, + } + + // run tests + for _, test := range tests { + got := test.build.Nullify() + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Nullify is %v, want %v", got, test.want) + } + } +} + +func TestTypes_Build_ToAPI(t *testing.T) { + // setup types + want := new(api.Build) + + want.SetID(1) + want.SetRepo(testRepo().ToAPI()) + want.SetPipelineID(1) + want.SetNumber(1) + want.SetParent(1) + want.SetEvent("push") + want.SetEventAction("") + want.SetStatus("running") + want.SetError("") + want.SetEnqueued(1563474077) + want.SetCreated(1563474076) + want.SetStarted(1563474078) + want.SetFinished(1563474079) + want.SetDeploy("") + want.SetDeployNumber(0) + want.SetDeployPayload(nil) + want.SetClone("https://github.com/github/octocat.git") + want.SetSource("https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163") + want.SetTitle("push received from https://github.com/github/octocat") + want.SetMessage("First commit...") + want.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") + want.SetSender("OctoKitty") + want.SetAuthor("OctoKitty") + want.SetEmail("OctoKitty@github.com") + want.SetLink("https://example.company.com/github/octocat/1") + want.SetBranch("main") + want.SetRef("refs/heads/main") + want.SetBaseRef("") + want.SetHeadRef("") + want.SetHost("example.company.com") + want.SetRuntime("docker") + want.SetDistribution("linux") + want.SetDeployPayload(raw.StringSliceMap{"foo": "test1", "bar": "test2"}) + want.SetApprovedAt(1563474076) + want.SetApprovedBy("OctoCat") + + // run test + got := testBuild().ToAPI() + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("ToAPI() mismatch (-want +got):\n%s", diff) + } +} + +func TestTypes_Build_Validate(t *testing.T) { + // setup tests + tests := []struct { + failure bool + build *Build + }{ + { + failure: false, + build: testBuild(), + }, + { // no repo_id set for build + failure: true, + build: &Build{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Number: sql.NullInt32{Int32: 1, Valid: true}, + }, + }, + { // no number set for build + failure: true, + build: &Build{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + RepoID: sql.NullInt64{Int64: 1, Valid: true}, + }, + }, + } + + // run tests + for _, test := range tests { + err := test.build.Validate() + + if test.failure { + if err == nil { + t.Errorf("Validate should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Validate returned err: %v", err) + } + } +} + +func TestTypes_Build_BuildFromAPI(t *testing.T) { + // setup types + b := new(api.Build) + + r := testutils.APIRepo() + r.SetID(1) + + b.SetID(1) + b.SetRepo(r) + b.SetPipelineID(1) + b.SetNumber(1) + b.SetParent(1) + b.SetEvent("push") + b.SetEventAction("") + b.SetStatus("running") + b.SetError("") + b.SetEnqueued(1563474077) + b.SetCreated(1563474076) + b.SetStarted(1563474078) + b.SetFinished(1563474079) + b.SetDeploy("") + b.SetDeployNumber(0) + b.SetDeployPayload(nil) + b.SetClone("https://github.com/github/octocat.git") + b.SetSource("https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163") + b.SetTitle("push received from https://github.com/github/octocat") + b.SetMessage("First commit...") + b.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") + b.SetSender("OctoKitty") + b.SetAuthor("OctoKitty") + b.SetEmail("OctoKitty@github.com") + b.SetLink("https://example.company.com/github/octocat/1") + b.SetBranch("main") + b.SetRef("refs/heads/main") + b.SetBaseRef("") + b.SetHeadRef("") + b.SetHost("example.company.com") + b.SetRuntime("docker") + b.SetDistribution("linux") + b.SetDeployPayload(raw.StringSliceMap{"foo": "test1", "bar": "test2"}) + b.SetApprovedAt(1563474076) + b.SetApprovedBy("OctoCat") + + want := testBuild() + want.Repo = Repo{} + + // run test + got := BuildFromAPI(b) + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("FromAPI() mismatch (-want +got):\n%s", diff) + } +} + +func randomString(n int) string { + var letter = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + + b := make([]rune, n) + for i := range b { + //nolint:gosec // accepting weak RNG for test + b[i] = letter[rand.Intn(len(letter))] + } + + return string(b) +} + +// testBuild is a test helper function to create a Build +// type with all fields set to a fake value. +func testBuild() *Build { + return &Build{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + RepoID: sql.NullInt64{Int64: 1, Valid: true}, + PipelineID: sql.NullInt64{Int64: 1, Valid: true}, + Number: sql.NullInt32{Int32: 1, Valid: true}, + Parent: sql.NullInt32{Int32: 1, Valid: true}, + Event: sql.NullString{String: "push", Valid: true}, + EventAction: sql.NullString{String: "", Valid: false}, + Status: sql.NullString{String: "running", Valid: true}, + Error: sql.NullString{String: "", Valid: false}, + Enqueued: sql.NullInt64{Int64: 1563474077, Valid: true}, + Created: sql.NullInt64{Int64: 1563474076, Valid: true}, + Started: sql.NullInt64{Int64: 1563474078, Valid: true}, + Finished: sql.NullInt64{Int64: 1563474079, Valid: true}, + Deploy: sql.NullString{String: "", Valid: false}, + DeployNumber: sql.NullInt64{Int64: 0, Valid: false}, + DeployPayload: raw.StringSliceMap{"foo": "test1", "bar": "test2"}, + Clone: sql.NullString{String: "https://github.com/github/octocat.git", Valid: true}, + Source: sql.NullString{String: "https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163", Valid: true}, + Title: sql.NullString{String: "push received from https://github.com/github/octocat", Valid: true}, + Message: sql.NullString{String: "First commit...", Valid: true}, + Commit: sql.NullString{String: "48afb5bdc41ad69bf22588491333f7cf71135163", Valid: true}, + Sender: sql.NullString{String: "OctoKitty", Valid: true}, + Author: sql.NullString{String: "OctoKitty", Valid: true}, + Email: sql.NullString{String: "OctoKitty@github.com", Valid: true}, + Link: sql.NullString{String: "https://example.company.com/github/octocat/1", Valid: true}, + Branch: sql.NullString{String: "main", Valid: true}, + Ref: sql.NullString{String: "refs/heads/main", Valid: true}, + BaseRef: sql.NullString{String: "", Valid: false}, + HeadRef: sql.NullString{String: "", Valid: false}, + Host: sql.NullString{String: "example.company.com", Valid: true}, + Runtime: sql.NullString{String: "docker", Valid: true}, + Distribution: sql.NullString{String: "linux", Valid: true}, + ApprovedAt: sql.NullInt64{Int64: 1563474076, Valid: true}, + ApprovedBy: sql.NullString{String: "OctoCat", Valid: true}, + + Repo: *testRepo(), + } +} diff --git a/database/types/dashboard.go b/database/types/dashboard.go new file mode 100644 index 000000000..181824b7e --- /dev/null +++ b/database/types/dashboard.go @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + "errors" + "fmt" + + "github.com/google/uuid" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/util" +) + +var ( + // ErrEmptyDashName defines the error type when a + // User type has an empty Name field provided. + ErrEmptyDashName = errors.New("empty dashboard name provided") + + // ErrExceededAdminLimit defines the error type when a + // User type has Admins field provided that exceeds the database limit. + ErrExceededAdminLimit = errors.New("exceeded admins limit") +) + +type ( + // Dashboard is the database representation of a dashboard. + Dashboard struct { + ID uuid.UUID `gorm:"type:uuid;default:uuid_generate_v4()"` + Name sql.NullString `sql:"name"` + CreatedAt sql.NullInt64 `sql:"created_at"` + CreatedBy sql.NullString `sql:"created_by"` + UpdatedAt sql.NullInt64 `sql:"updated_at"` + UpdatedBy sql.NullString `sql:"updated_by"` + Admins AdminsJSON + Repos DashReposJSON + } + + DashReposJSON []*api.DashboardRepo + AdminsJSON []*api.User +) + +// Value - Implementation of valuer for database/sql for DashReposJSON. +func (r DashReposJSON) Value() (driver.Value, error) { + valueString, err := json.Marshal(r) + return string(valueString), err +} + +// Scan - Implement the database/sql scanner interface for DashReposJSON. +func (r *DashReposJSON) Scan(value interface{}) error { + switch v := value.(type) { + case []byte: + return json.Unmarshal(v, &r) + case string: + return json.Unmarshal([]byte(v), &r) + default: + return fmt.Errorf("wrong type for repos: %T", v) + } +} + +// Value - Implementation of valuer for database/sql for AdminsJSON. +func (a AdminsJSON) Value() (driver.Value, error) { + valueString, err := json.Marshal(a) + return string(valueString), err +} + +// Scan - Implement the database/sql scanner interface for AdminsJSON. +func (a *AdminsJSON) Scan(value interface{}) error { + switch v := value.(type) { + case []byte: + return json.Unmarshal(v, &a) + case string: + return json.Unmarshal([]byte(v), &a) + default: + return fmt.Errorf("wrong type for admins: %T", v) + } +} + +// Nullify ensures the valid flag for +// the sql.Null types are properly set. +// +// When a field within the Dashboard type is the zero +// value for the field, the valid flag is set to +// false causing it to be NULL in the database. +func (d *Dashboard) Nullify() *Dashboard { + if d == nil { + return nil + } + + // check if the Name field should be false + if len(d.Name.String) == 0 { + d.Name.Valid = false + } + + // check if the CreatedAt field should be false + if d.CreatedAt.Int64 == 0 { + d.CreatedAt.Valid = false + } + + // check if the CreatedBy field should be false + if len(d.CreatedBy.String) == 0 { + d.CreatedBy.Valid = false + } + + // check if the UpdatedAt field should be false + if d.UpdatedAt.Int64 == 0 { + d.UpdatedAt.Valid = false + } + + // check if the UpdatedBy field should be false + if len(d.UpdatedBy.String) == 0 { + d.UpdatedBy.Valid = false + } + + return d +} + +// ToAPI converts the Dashboard type +// to an API Dashboard type. +func (d *Dashboard) ToAPI() *api.Dashboard { + dashboard := new(api.Dashboard) + + dashboard.SetID(d.ID.String()) + dashboard.SetName(d.Name.String) + dashboard.SetAdmins(d.Admins) + dashboard.SetCreatedAt(d.CreatedAt.Int64) + dashboard.SetCreatedBy(d.CreatedBy.String) + dashboard.SetUpdatedAt(d.UpdatedAt.Int64) + dashboard.SetUpdatedBy(d.UpdatedBy.String) + dashboard.SetRepos(d.Repos) + + return dashboard +} + +// Validate verifies the necessary fields for +// the Dashboard type are populated correctly. +func (d *Dashboard) Validate() error { + // verify the Name field is populated + if len(d.Name.String) == 0 { + return ErrEmptyDashName + } + + // ensure that all Dashboard string fields + // that can be returned as JSON are sanitized + // to avoid unsafe HTML content + d.Name = sql.NullString{String: util.Sanitize(d.Name.String), Valid: d.Name.Valid} + + return nil +} + +// DashboardFromAPI converts the API Dashboard type +// to a database Dashboard type. +func DashboardFromAPI(d *api.Dashboard) *Dashboard { + var ( + id uuid.UUID + err error + ) + + if d.GetID() == "" { + id = uuid.New() + } else { + id, err = uuid.Parse(d.GetID()) + if err != nil { + return nil + } + } + + dashboard := &Dashboard{ + ID: id, + Name: sql.NullString{String: d.GetName(), Valid: true}, + CreatedAt: sql.NullInt64{Int64: d.GetCreatedAt(), Valid: true}, + CreatedBy: sql.NullString{String: d.GetCreatedBy(), Valid: true}, + UpdatedAt: sql.NullInt64{Int64: d.GetUpdatedAt(), Valid: true}, + UpdatedBy: sql.NullString{String: d.GetUpdatedBy(), Valid: true}, + Admins: d.GetAdmins(), + Repos: d.GetRepos(), + } + + return dashboard.Nullify() +} diff --git a/database/types/dashboard_test.go b/database/types/dashboard_test.go new file mode 100644 index 000000000..f163e8b9c --- /dev/null +++ b/database/types/dashboard_test.go @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "reflect" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/uuid" + + api "github.com/go-vela/server/api/types" +) + +func TestTypes_Dashboard_Nullify(t *testing.T) { + // setup types + var h *Dashboard + + want := &Dashboard{ + Name: sql.NullString{String: "", Valid: false}, + CreatedAt: sql.NullInt64{Int64: 0, Valid: false}, + CreatedBy: sql.NullString{String: "", Valid: false}, + UpdatedAt: sql.NullInt64{Int64: 0, Valid: false}, + UpdatedBy: sql.NullString{String: "", Valid: false}, + } + + // setup tests + tests := []struct { + dashboard *Dashboard + want *Dashboard + }{ + { + dashboard: testDashboard(), + want: testDashboard(), + }, + { + dashboard: h, + want: nil, + }, + { + dashboard: new(Dashboard), + want: want, + }, + } + + // run tests + for _, test := range tests { + got := test.dashboard.Nullify() + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Nullify is %v, want %v", got, test.want) + } + } +} + +func TestTypes_Dashboard_ToAPI(t *testing.T) { + // setup types + want := new(api.Dashboard) + want.SetID("c8da1302-07d6-11ea-882f-4893bca275b8") + want.SetName("vela") + want.SetCreatedAt(1) + want.SetCreatedBy("octocat") + want.SetUpdatedAt(2) + want.SetUpdatedBy("octokitty") + want.SetAdmins(testAdminsJSON()) + want.SetRepos(testDashReposJSON()) + + uuid, _ := uuid.Parse("c8da1302-07d6-11ea-882f-4893bca275b8") + h := &Dashboard{ + ID: uuid, + Name: sql.NullString{String: "vela", Valid: true}, + CreatedAt: sql.NullInt64{Int64: 1, Valid: true}, + CreatedBy: sql.NullString{String: "octocat", Valid: true}, + UpdatedAt: sql.NullInt64{Int64: 2, Valid: true}, + UpdatedBy: sql.NullString{String: "octokitty", Valid: true}, + Admins: testAdminsJSON(), + Repos: testDashReposJSON(), + } + + // run test + got := h.ToAPI() + + if !reflect.DeepEqual(got, want) { + t.Errorf("ToAPI is %v, want %v", got, want) + } +} + +func TestTypes_Dashboard_Validate(t *testing.T) { + uuid, _ := uuid.Parse("c8da1302-07d6-11ea-882f-4893bca275b8") + + // setup tests + tests := []struct { + failure bool + dashboard *Dashboard + }{ + { + failure: false, + dashboard: testDashboard(), + }, + { // no name set for dashboard + failure: true, + dashboard: &Dashboard{ + ID: uuid, + }, + }, + } + + // run tests + for _, test := range tests { + err := test.dashboard.Validate() + + if test.failure { + if err == nil { + t.Errorf("Validate should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Validate returned err: %v", err) + } + } +} + +func TestTypes_DashboardFromAPI(t *testing.T) { + uuid, err := uuid.Parse("c8da1302-07d6-11ea-882f-4893bca275b8") + if err != nil { + t.Errorf("error parsing uuid: %v", err) + } + + // setup types + want := &Dashboard{ + ID: uuid, + Name: sql.NullString{String: "vela", Valid: true}, + CreatedAt: sql.NullInt64{Int64: 1, Valid: true}, + CreatedBy: sql.NullString{String: "octocat", Valid: true}, + UpdatedAt: sql.NullInt64{Int64: 2, Valid: true}, + UpdatedBy: sql.NullString{String: "octokitty", Valid: true}, + Admins: testAdminsJSON(), + Repos: testDashReposJSON(), + } + + d := new(api.Dashboard) + d.SetID("c8da1302-07d6-11ea-882f-4893bca275b8") + d.SetName("vela") + d.SetCreatedAt(1) + d.SetCreatedBy("octocat") + d.SetUpdatedAt(2) + d.SetUpdatedBy("octokitty") + d.SetAdmins(testAdminsJSON()) + d.SetRepos(testDashReposJSON()) + + // run test + got := DashboardFromAPI(d) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("DashboardFromAPI() mismatch (-want +got):\n%s", diff) + } + + // test empty uuid results in generated uuid + d.SetID("") + + //nolint:staticcheck // linter is lying + got = DashboardFromAPI(d) + + if len(got.ID) != 16 { + t.Errorf("Length is %d", len(got.ID)) + } + + // test poorly formed uuid results in nil dashboard + d.SetID("123-abc") + + got = DashboardFromAPI(d) + + if got != nil { + t.Errorf("DashboardFromAPI should have returned nil") + } +} + +// testDashboard is a test helper function to create a Dashboard +// type with all fields set to a fake value. +func testDashboard() *Dashboard { + uuid, _ := uuid.Parse("c8da1302-07d6-11ea-882f-4893bca275b8") + + return &Dashboard{ + ID: uuid, + Name: sql.NullString{String: "vela", Valid: true}, + CreatedAt: sql.NullInt64{Int64: time.Now().UTC().Unix(), Valid: true}, + CreatedBy: sql.NullString{String: "octocat", Valid: true}, + UpdatedAt: sql.NullInt64{Int64: time.Now().UTC().Unix(), Valid: true}, + UpdatedBy: sql.NullString{String: "octokitty", Valid: true}, + Admins: testAdminsJSON(), + Repos: testDashReposJSON(), + } +} + +// testDashReposJSON is a test helper function to create a DashReposJSON +// type with all fields set to a fake value. +func testDashReposJSON() DashReposJSON { + d := new(api.DashboardRepo) + + d.SetName("go-vela/server") + d.SetID(1) + d.SetBranches([]string{"main"}) + d.SetEvents([]string{"push", "tag"}) + + return DashReposJSON{d} +} + +// testAdminsJSON is a test helper function to create a DashReposJSON +// type with all fields set to a fake value. +func testAdminsJSON() AdminsJSON { + u1 := new(api.User) + + u1.SetName("octocat") + u1.SetID(1) + u1.SetActive(true) + u1.SetToken("foo") + + u2 := new(api.User) + + u2.SetName("octokitty") + u2.SetID(2) + u2.SetActive(true) + u2.SetToken("bar") + + return AdminsJSON{u1, u2} +} diff --git a/database/types/queue_build.go b/database/types/queue_build.go new file mode 100644 index 000000000..51f0cfd0a --- /dev/null +++ b/database/types/queue_build.go @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + + api "github.com/go-vela/server/api/types" +) + +// QueueBuild is the database representation of the builds in the queue. +type QueueBuild struct { + Status sql.NullString `sql:"status"` + Number sql.NullInt32 `sql:"number"` + Created sql.NullInt64 `sql:"created"` + FullName sql.NullString `sql:"full_name"` +} + +// ToAPI converts the QueueBuild type +// to a API QueueBuild type. +func (b *QueueBuild) ToAPI() *api.QueueBuild { + buildQueue := new(api.QueueBuild) + + buildQueue.SetStatus(b.Status.String) + buildQueue.SetNumber(b.Number.Int32) + buildQueue.SetCreated(b.Created.Int64) + buildQueue.SetFullName(b.FullName.String) + + return buildQueue +} + +// QueueBuildFromAPI converts the API QueueBuild type +// to a database build queue type. +func QueueBuildFromAPI(b *api.QueueBuild) *QueueBuild { + buildQueue := &QueueBuild{ + Status: sql.NullString{String: b.GetStatus(), Valid: true}, + Number: sql.NullInt32{Int32: b.GetNumber(), Valid: true}, + Created: sql.NullInt64{Int64: b.GetCreated(), Valid: true}, + FullName: sql.NullString{String: b.GetFullName(), Valid: true}, + } + + return buildQueue +} diff --git a/database/types/queue_build_test.go b/database/types/queue_build_test.go new file mode 100644 index 000000000..55a413230 --- /dev/null +++ b/database/types/queue_build_test.go @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "reflect" + "testing" + + api "github.com/go-vela/server/api/types" +) + +func TestTypes_QueueBuild_ToAPI(t *testing.T) { + // setup types + want := new(api.QueueBuild) + + want.SetNumber(1) + want.SetStatus("running") + want.SetCreated(1563474076) + want.SetFullName("github/octocat") + + // run test + got := testQueueBuild().ToAPI() + + if !reflect.DeepEqual(got, want) { + t.Errorf("ToAPI is %v, want %v", got, want) + } +} + +func TestTypes_QueueBuild_FromAPI(t *testing.T) { + // setup types + b := new(api.QueueBuild) + + b.SetNumber(1) + b.SetStatus("running") + b.SetCreated(1563474076) + b.SetFullName("github/octocat") + + want := testQueueBuild() + + // run test + got := QueueBuildFromAPI(b) + + if !reflect.DeepEqual(got, want) { + t.Errorf("QueueBuildFromAPI is %v, want %v", got, want) + } +} + +// testQueueBuild is a test helper function to create a QueueBuild +// type with all fields set to a fake value. +func testQueueBuild() *QueueBuild { + return &QueueBuild{ + Number: sql.NullInt32{Int32: 1, Valid: true}, + Status: sql.NullString{String: "running", Valid: true}, + Created: sql.NullInt64{Int64: 1563474076, Valid: true}, + FullName: sql.NullString{String: "github/octocat", Valid: true}, + } +} diff --git a/database/types/repo.go b/database/types/repo.go new file mode 100644 index 000000000..e3780f851 --- /dev/null +++ b/database/types/repo.go @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "encoding/base64" + "errors" + + "github.com/lib/pq" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" +) + +var ( + // ErrEmptyRepoFullName defines the error type when a + // Repo type has an empty FullName field provided. + ErrEmptyRepoFullName = errors.New("empty repo full_name provided") + + // ErrEmptyRepoHash defines the error type when a + // Repo type has an empty Hash field provided. + ErrEmptyRepoHash = errors.New("empty repo hash provided") + + // ErrEmptyRepoName defines the error type when a + // Repo type has an empty Name field provided. + ErrEmptyRepoName = errors.New("empty repo name provided") + + // ErrEmptyRepoOrg defines the error type when a + // Repo type has an empty Org field provided. + ErrEmptyRepoOrg = errors.New("empty repo org provided") + + // ErrEmptyRepoUserID defines the error type when a + // Repo type has an empty UserID field provided. + ErrEmptyRepoUserID = errors.New("empty repo user_id provided") + + // ErrEmptyRepoVisibility defines the error type when a + // Repo type has an empty Visibility field provided. + ErrEmptyRepoVisibility = errors.New("empty repo visibility provided") + + // ErrExceededTopicsLimit defines the error type when a + // Repo type has Topics field provided that exceeds the database limit. + ErrExceededTopicsLimit = errors.New("exceeded topics limit") +) + +// Repo is the database representation of a repo. +type Repo struct { + ID sql.NullInt64 `sql:"id"` + UserID sql.NullInt64 `sql:"user_id"` + Hash sql.NullString `sql:"hash"` + Org sql.NullString `sql:"org"` + Name sql.NullString `sql:"name"` + FullName sql.NullString `sql:"full_name"` + Link sql.NullString `sql:"link"` + Clone sql.NullString `sql:"clone"` + Branch sql.NullString `sql:"branch"` + Topics pq.StringArray `sql:"topics" gorm:"type:varchar(1020)"` + BuildLimit sql.NullInt64 `sql:"build_limit"` + Timeout sql.NullInt64 `sql:"timeout"` + Counter sql.NullInt32 `sql:"counter"` + Visibility sql.NullString `sql:"visibility"` + Private sql.NullBool `sql:"private"` + Trusted sql.NullBool `sql:"trusted"` + Active sql.NullBool `sql:"active"` + AllowEvents sql.NullInt64 `sql:"allow_events"` + PipelineType sql.NullString `sql:"pipeline_type"` + PreviousName sql.NullString `sql:"previous_name"` + ApproveBuild sql.NullString `sql:"approve_build"` + + Owner User `gorm:"foreignKey:UserID"` +} + +// Decrypt will manipulate the existing repo hash by +// base64 decoding that value. Then, a AES-256 cipher +// block is created from the encryption key in order to +// decrypt the base64 decoded secret value. +func (r *Repo) Decrypt(key string) error { + // base64 decode the encrypted repo hash + decoded, err := base64.StdEncoding.DecodeString(r.Hash.String) + if err != nil { + return err + } + + // decrypt the base64 decoded repo hash + decrypted, err := util.Decrypt(key, decoded) + if err != nil { + return err + } + + // set the decrypted repo hash + r.Hash = sql.NullString{ + String: string(decrypted), + Valid: true, + } + + // decrypt owner + err = r.Owner.Decrypt(key) + if err != nil { + return err + } + + return nil +} + +// Encrypt will manipulate the existing repo hash by +// creating a AES-256 cipher block from the encryption +// key in order to encrypt the repo hash. Then, the +// repo hash is base64 encoded for transport across +// network boundaries. +func (r *Repo) Encrypt(key string) error { + // encrypt the repo hash + encrypted, err := util.Encrypt(key, []byte(r.Hash.String)) + if err != nil { + return err + } + + // base64 encode the encrypted repo hash to make it network safe + r.Hash = sql.NullString{ + String: base64.StdEncoding.EncodeToString(encrypted), + Valid: true, + } + + return nil +} + +// Nullify ensures the valid flag for +// the sql.Null types are properly set. +// +// When a field within the Repo type is the zero +// value for the field, the valid flag is set to +// false causing it to be NULL in the database. +func (r *Repo) Nullify() *Repo { + if r == nil { + return nil + } + + // check if the ID field should be false + if r.ID.Int64 == 0 { + r.ID.Valid = false + } + + // check if the UserID field should be false + if r.UserID.Int64 == 0 { + r.UserID.Valid = false + } + + // check if the Hash field should be false + if len(r.Hash.String) == 0 { + r.Hash.Valid = false + } + + // check if the Org field should be false + if len(r.Org.String) == 0 { + r.Org.Valid = false + } + + // check if the Name field should be false + if len(r.Name.String) == 0 { + r.Name.Valid = false + } + + // check if the FullName field should be false + if len(r.FullName.String) == 0 { + r.FullName.Valid = false + } + + // check if the Link field should be false + if len(r.Link.String) == 0 { + r.Link.Valid = false + } + + // check if the Clone field should be false + if len(r.Clone.String) == 0 { + r.Clone.Valid = false + } + + // check if the Branch field should be false + if len(r.Branch.String) == 0 { + r.Branch.Valid = false + } + + // check if the BuildLimit field should be false + if r.BuildLimit.Int64 == 0 { + r.BuildLimit.Valid = false + } + + // check if the Timeout field should be false + if r.Timeout.Int64 == 0 { + r.Timeout.Valid = false + } + + // check if the AllowEvents field should be false + if r.AllowEvents.Int64 == 0 { + r.AllowEvents.Valid = false + } + + // check if the Visibility field should be false + if len(r.Visibility.String) == 0 { + r.Visibility.Valid = false + } + + // check if the PipelineType field should be false + if len(r.PipelineType.String) == 0 { + r.PipelineType.Valid = false + } + + // check if the PreviousName field should be false + if len(r.PreviousName.String) == 0 { + r.PreviousName.Valid = false + } + + // check if the ApproveForkBuild field should be false + if len(r.ApproveBuild.String) == 0 { + r.ApproveBuild.Valid = false + } + + return r +} + +// ToAPI converts the Repo type +// to an API Repo type. +func (r *Repo) ToAPI() *api.Repo { + repo := new(api.Repo) + + repo.SetID(r.ID.Int64) + repo.SetOwner(r.Owner.ToAPI().Crop()) + repo.SetHash(r.Hash.String) + repo.SetOrg(r.Org.String) + repo.SetName(r.Name.String) + repo.SetFullName(r.FullName.String) + repo.SetLink(r.Link.String) + repo.SetClone(r.Clone.String) + repo.SetBranch(r.Branch.String) + repo.SetTopics(r.Topics) + repo.SetBuildLimit(r.BuildLimit.Int64) + repo.SetTimeout(r.Timeout.Int64) + repo.SetCounter(int(r.Counter.Int32)) + repo.SetVisibility(r.Visibility.String) + repo.SetPrivate(r.Private.Bool) + repo.SetTrusted(r.Trusted.Bool) + repo.SetActive(r.Active.Bool) + repo.SetAllowEvents(api.NewEventsFromMask(r.AllowEvents.Int64)) + repo.SetPipelineType(r.PipelineType.String) + repo.SetPreviousName(r.PreviousName.String) + repo.SetApproveBuild(r.ApproveBuild.String) + + return repo +} + +// Validate verifies the necessary fields for +// the Repo type are populated correctly. +func (r *Repo) Validate() error { + // verify the UserID field is populated + if r.UserID.Int64 <= 0 { + return ErrEmptyRepoUserID + } + + // verify the Hash field is populated + if len(r.Hash.String) == 0 { + return ErrEmptyRepoHash + } + + // verify the Org field is populated + if len(r.Org.String) == 0 { + return ErrEmptyRepoOrg + } + + // verify the Name field is populated + if len(r.Name.String) == 0 { + return ErrEmptyRepoName + } + + // verify the FullName field is populated + if len(r.FullName.String) == 0 { + return ErrEmptyRepoFullName + } + + // verify the Visibility field is populated + if len(r.Visibility.String) == 0 { + return ErrEmptyRepoVisibility + } + + // calculate total size of favorites while sanitizing entries + total := 0 + + for i, t := range r.Topics { + r.Topics[i] = util.Sanitize(t) + total += len(t) + } + + // verify the Favorites field is within the database constraints + // len is to factor in number of comma separators included in the database field, + // removing 1 due to the last item not having an appended comma + if (total + len(r.Topics) - 1) > constants.TopicsMaxSize { + return ErrExceededTopicsLimit + } + + // ensure that all Repo string fields + // that can be returned as JSON are sanitized + // to avoid unsafe HTML content + r.Org = sql.NullString{String: util.Sanitize(r.Org.String), Valid: r.Org.Valid} + r.Name = sql.NullString{String: util.Sanitize(r.Name.String), Valid: r.Name.Valid} + r.FullName = sql.NullString{String: util.Sanitize(r.FullName.String), Valid: r.FullName.Valid} + r.Link = sql.NullString{String: util.Sanitize(r.Link.String), Valid: r.Link.Valid} + r.Clone = sql.NullString{String: util.Sanitize(r.Clone.String), Valid: r.Clone.Valid} + r.Branch = sql.NullString{String: util.Sanitize(r.Branch.String), Valid: r.Branch.Valid} + r.Visibility = sql.NullString{String: util.Sanitize(r.Visibility.String), Valid: r.Visibility.Valid} + r.PipelineType = sql.NullString{String: util.Sanitize(r.PipelineType.String), Valid: r.PipelineType.Valid} + + return nil +} + +// RepoFromAPI converts the API Repo type +// to a database repo type. +func RepoFromAPI(r *api.Repo) *Repo { + repo := &Repo{ + ID: sql.NullInt64{Int64: r.GetID(), Valid: true}, + UserID: sql.NullInt64{Int64: r.GetOwner().GetID(), Valid: true}, + Hash: sql.NullString{String: r.GetHash(), Valid: true}, + Org: sql.NullString{String: r.GetOrg(), Valid: true}, + Name: sql.NullString{String: r.GetName(), Valid: true}, + FullName: sql.NullString{String: r.GetFullName(), Valid: true}, + Link: sql.NullString{String: r.GetLink(), Valid: true}, + Clone: sql.NullString{String: r.GetClone(), Valid: true}, + Branch: sql.NullString{String: r.GetBranch(), Valid: true}, + Topics: pq.StringArray(r.GetTopics()), + BuildLimit: sql.NullInt64{Int64: r.GetBuildLimit(), Valid: true}, + Timeout: sql.NullInt64{Int64: r.GetTimeout(), Valid: true}, + Counter: sql.NullInt32{Int32: int32(r.GetCounter()), Valid: true}, + Visibility: sql.NullString{String: r.GetVisibility(), Valid: true}, + Private: sql.NullBool{Bool: r.GetPrivate(), Valid: true}, + Trusted: sql.NullBool{Bool: r.GetTrusted(), Valid: true}, + Active: sql.NullBool{Bool: r.GetActive(), Valid: true}, + AllowEvents: sql.NullInt64{Int64: r.GetAllowEvents().ToDatabase(), Valid: true}, + PipelineType: sql.NullString{String: r.GetPipelineType(), Valid: true}, + PreviousName: sql.NullString{String: r.GetPreviousName(), Valid: true}, + ApproveBuild: sql.NullString{String: r.GetApproveBuild(), Valid: true}, + } + + return repo.Nullify() +} diff --git a/database/types/repo_test.go b/database/types/repo_test.go new file mode 100644 index 000000000..f060e9141 --- /dev/null +++ b/database/types/repo_test.go @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" + "github.com/go-vela/types/constants" +) + +func TestTypes_Repo_Decrypt(t *testing.T) { + // setup types + key := "C639A572E14D5075C526FDDD43E4ECF6" + encrypted := testRepo() + + err := encrypted.Encrypt(key) + if err != nil { + t.Errorf("unable to encrypt repo: %v", err) + } + + err = encrypted.Owner.Encrypt(key) + if err != nil { + t.Errorf("unable to encrypt user: %v", err) + } + + // setup tests + tests := []struct { + failure bool + key string + repo Repo + }{ + { + failure: false, + key: key, + repo: *encrypted, + }, + { + failure: true, + key: "", + repo: *encrypted, + }, + { + failure: true, + key: key, + repo: *testRepo(), + }, + } + + // run tests + for _, test := range tests { + err := test.repo.Decrypt(test.key) + + if test.failure { + if err == nil { + t.Errorf("Decrypt should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Decrypt returned err: %v", err) + } + } +} + +func TestTypes_Repo_Encrypt(t *testing.T) { + // setup types + key := "C639A572E14D5075C526FDDD43E4ECF6" + + // setup tests + tests := []struct { + failure bool + key string + repo *Repo + }{ + { + failure: false, + key: key, + repo: testRepo(), + }, + { + failure: true, + key: "", + repo: testRepo(), + }, + } + + // run tests + for _, test := range tests { + err := test.repo.Encrypt(test.key) + + if test.failure { + if err == nil { + t.Errorf("Encrypt should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Encrypt returned err: %v", err) + } + } +} + +func TestTypes_Repo_Nullify(t *testing.T) { + // setup types + var r *Repo + + want := &Repo{ + ID: sql.NullInt64{Int64: 0, Valid: false}, + UserID: sql.NullInt64{Int64: 0, Valid: false}, + Hash: sql.NullString{String: "", Valid: false}, + Org: sql.NullString{String: "", Valid: false}, + Name: sql.NullString{String: "", Valid: false}, + FullName: sql.NullString{String: "", Valid: false}, + Link: sql.NullString{String: "", Valid: false}, + Clone: sql.NullString{String: "", Valid: false}, + Branch: sql.NullString{String: "", Valid: false}, + Timeout: sql.NullInt64{Int64: 0, Valid: false}, + AllowEvents: sql.NullInt64{Int64: 0, Valid: false}, + Visibility: sql.NullString{String: "", Valid: false}, + PipelineType: sql.NullString{String: "", Valid: false}, + ApproveBuild: sql.NullString{String: "", Valid: false}, + } + + // setup tests + tests := []struct { + repo *Repo + want *Repo + }{ + { + repo: testRepo(), + want: testRepo(), + }, + { + repo: r, + want: nil, + }, + { + repo: new(Repo), + want: want, + }, + } + + // run tests + for _, test := range tests { + got := test.repo.Nullify() + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Nullify is %v, want %v", got, test.want) + } + } +} + +func TestTypes_Repo_ToAPI(t *testing.T) { + // setup types + want := new(api.Repo) + e := api.NewEventsFromMask(1) + + owner := testutils.APIUser().Crop() + owner.SetID(1) + owner.SetName("octocat") + owner.SetActive(true) + owner.SetToken("superSecretToken") + owner.SetRefreshToken("superSecretRefreshToken") + + want.SetID(1) + want.SetOwner(owner) + want.SetHash("superSecretHash") + want.SetOrg("github") + want.SetName("octocat") + want.SetFullName("github/octocat") + want.SetLink("https://github.com/github/octocat") + want.SetClone("https://github.com/github/octocat.git") + want.SetBranch("main") + want.SetTopics([]string{"cloud", "security"}) + want.SetBuildLimit(10) + want.SetTimeout(30) + want.SetCounter(0) + want.SetVisibility("public") + want.SetPrivate(false) + want.SetTrusted(false) + want.SetActive(true) + want.SetAllowEvents(e) + want.SetPipelineType("yaml") + want.SetPreviousName("oldName") + want.SetApproveBuild(constants.ApproveNever) + + // run test + got := testRepo().ToAPI() + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("ToAPI() mismatch (-want +got):\n%s", diff) + } +} + +func TestTypes_Repo_Validate(t *testing.T) { + // setup types + topics := []string{} + longTopic := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + + for len(topics) < 21 { + topics = append(topics, longTopic) + } + + // setup tests + tests := []struct { + failure bool + repo *Repo + }{ + { + failure: false, + repo: testRepo(), + }, + { // no user_id set for repo + failure: true, + repo: &Repo{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, + Org: sql.NullString{String: "github", Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + FullName: sql.NullString{String: "github/octocat", Valid: true}, + Visibility: sql.NullString{String: "public", Valid: true}, + }, + }, + { // no hash set for repo + failure: true, + repo: &Repo{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + UserID: sql.NullInt64{Int64: 1, Valid: true}, + Org: sql.NullString{String: "github", Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + FullName: sql.NullString{String: "github/octocat", Valid: true}, + Visibility: sql.NullString{String: "public", Valid: true}, + }, + }, + { // no org set for repo + failure: true, + repo: &Repo{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + UserID: sql.NullInt64{Int64: 1, Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + FullName: sql.NullString{String: "github/octocat", Valid: true}, + Visibility: sql.NullString{String: "public", Valid: true}, + }, + }, + { // no name set for repo + failure: true, + repo: &Repo{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + UserID: sql.NullInt64{Int64: 1, Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, + Org: sql.NullString{String: "github", Valid: true}, + FullName: sql.NullString{String: "github/octocat", Valid: true}, + Visibility: sql.NullString{String: "public", Valid: true}, + }, + }, + { // no full_name set for repo + failure: true, + repo: &Repo{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + UserID: sql.NullInt64{Int64: 1, Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, + Org: sql.NullString{String: "github", Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + Visibility: sql.NullString{String: "public", Valid: true}, + }, + }, + { // no visibility set for repo + failure: true, + repo: &Repo{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + UserID: sql.NullInt64{Int64: 1, Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, + Org: sql.NullString{String: "github", Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + FullName: sql.NullString{String: "github/octocat", Valid: true}, + }, + }, + { // topics exceed max size + failure: true, + repo: &Repo{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + UserID: sql.NullInt64{Int64: 1, Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, + Org: sql.NullString{String: "github", Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + FullName: sql.NullString{String: "github/octocat", Valid: true}, + Topics: topics, + }, + }, + } + + // run tests + for _, test := range tests { + err := test.repo.Validate() + + if test.failure { + if err == nil { + t.Errorf("Validate should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Validate returned err: %v", err) + } + } +} + +func TestTypes_RepoFromAPI(t *testing.T) { + // setup types + r := new(api.Repo) + owner := testutils.APIUser() + owner.SetID(1) + + r.SetID(1) + r.SetOwner(owner) + r.SetHash("superSecretHash") + r.SetOrg("github") + r.SetName("octocat") + r.SetFullName("github/octocat") + r.SetLink("https://github.com/github/octocat") + r.SetClone("https://github.com/github/octocat.git") + r.SetBranch("main") + r.SetTopics([]string{"cloud", "security"}) + r.SetBuildLimit(10) + r.SetTimeout(30) + r.SetCounter(0) + r.SetVisibility("public") + r.SetPrivate(false) + r.SetTrusted(false) + r.SetActive(true) + r.SetAllowEvents(api.NewEventsFromMask(1)) + r.SetPipelineType("yaml") + r.SetPreviousName("oldName") + r.SetApproveBuild(constants.ApproveNever) + + want := testRepo() + want.Owner = User{} + + // run test + got := RepoFromAPI(r) + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("FromAPI() mismatch (-want +got):\n%s", diff) + } +} + +// testRepo is a test helper function to create a Repo +// type with all fields set to a fake value. +func testRepo() *Repo { + return &Repo{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + UserID: sql.NullInt64{Int64: 1, Valid: true}, + Hash: sql.NullString{String: "superSecretHash", Valid: true}, + Org: sql.NullString{String: "github", Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + FullName: sql.NullString{String: "github/octocat", Valid: true}, + Link: sql.NullString{String: "https://github.com/github/octocat", Valid: true}, + Clone: sql.NullString{String: "https://github.com/github/octocat.git", Valid: true}, + Branch: sql.NullString{String: "main", Valid: true}, + Topics: []string{"cloud", "security"}, + BuildLimit: sql.NullInt64{Int64: 10, Valid: true}, + Timeout: sql.NullInt64{Int64: 30, Valid: true}, + Counter: sql.NullInt32{Int32: 0, Valid: true}, + Visibility: sql.NullString{String: "public", Valid: true}, + Private: sql.NullBool{Bool: false, Valid: true}, + Trusted: sql.NullBool{Bool: false, Valid: true}, + Active: sql.NullBool{Bool: true, Valid: true}, + AllowEvents: sql.NullInt64{Int64: 1, Valid: true}, + PipelineType: sql.NullString{String: "yaml", Valid: true}, + PreviousName: sql.NullString{String: "oldName", Valid: true}, + ApproveBuild: sql.NullString{String: constants.ApproveNever, Valid: true}, + + Owner: *testUser(), + } +} diff --git a/database/types/user.go b/database/types/user.go new file mode 100644 index 000000000..0bfd13e2a --- /dev/null +++ b/database/types/user.go @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "encoding/base64" + "errors" + "regexp" + + "github.com/lib/pq" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" +) + +var ( + // userRegex defines the regex pattern for validating + // the Name field for the User type. + userRegex = regexp.MustCompile("^[a-zA-Z0-9_-]{0,38}$") + + // ErrEmptyUserName defines the error type when a + // User type has an empty Name field provided. + ErrEmptyUserName = errors.New("empty user name provided") + + // ErrEmptyUserRefreshToken defines the error type when a + // User type has an empty RefreshToken field provided. + ErrEmptyUserRefreshToken = errors.New("empty user refresh token provided") + + // ErrEmptyUserToken defines the error type when a + // User type has an empty Token field provided. + ErrEmptyUserToken = errors.New("empty user token provided") + + // ErrInvalidUserName defines the error type when a + // User type has an invalid Name field provided. + ErrInvalidUserName = errors.New("invalid user name provided") + + // ErrExceededFavoritesLimit defines the error type when a + // User type has Favorites field provided that exceeds the database limit. + ErrExceededFavoritesLimit = errors.New("exceeded favorites limit") + + // ErrExceededDashboardsLimit defines the error type when a + // User type has Dashboards field provided that exceeds the database limit. + ErrExceededDashboardsLimit = errors.New("exceeded dashboards limit") +) + +// User is the database representation of a user. +type User struct { + ID sql.NullInt64 `sql:"id"` + Name sql.NullString `sql:"name"` + RefreshToken sql.NullString `sql:"refresh_token"` + Token sql.NullString `sql:"token"` + Favorites pq.StringArray `sql:"favorites" gorm:"type:varchar(5000)"` + Active sql.NullBool `sql:"active"` + Admin sql.NullBool `sql:"admin"` + Dashboards pq.StringArray `sql:"dashboards" gorm:"type:varchar(5000)"` +} + +// Decrypt will manipulate the existing user tokens by +// base64 decoding them. Then, a AES-256 cipher +// block is created from the encryption key in order to +// decrypt the base64 decoded user tokens. +func (u *User) Decrypt(key string) error { + // base64 decode the encrypted user token + decoded, err := base64.StdEncoding.DecodeString(u.Token.String) + if err != nil { + return err + } + + // decrypt the base64 decoded user token + decrypted, err := util.Decrypt(key, decoded) + if err != nil { + return err + } + + // set the decrypted user token + u.Token = sql.NullString{ + String: string(decrypted), + Valid: true, + } + + // base64 decode the encrypted user refresh token + decoded, err = base64.StdEncoding.DecodeString(u.RefreshToken.String) + if err != nil { + return err + } + + // decrypt the base64 decoded user refresh token + decrypted, err = util.Decrypt(key, decoded) + if err != nil { + return err + } + + // set the decrypted user refresh token + u.RefreshToken = sql.NullString{ + String: string(decrypted), + Valid: true, + } + + return nil +} + +// Encrypt will manipulate the existing user tokens by +// creating a AES-256 cipher block from the encryption +// key in order to encrypt the user tokens. Then, the +// user tokens are base64 encoded for transport across +// network boundaries. +func (u *User) Encrypt(key string) error { + // encrypt the user token + encrypted, err := util.Encrypt(key, []byte(u.Token.String)) + if err != nil { + return err + } + + // base64 encode the encrypted user token to make it network safe + u.Token = sql.NullString{ + String: base64.StdEncoding.EncodeToString(encrypted), + Valid: true, + } + + // encrypt the user refresh token + encrypted, err = util.Encrypt(key, []byte(u.RefreshToken.String)) + if err != nil { + return err + } + + // base64 encode the encrypted user refresh token to make it network safe + u.RefreshToken = sql.NullString{ + String: base64.StdEncoding.EncodeToString(encrypted), + Valid: true, + } + + return nil +} + +// Nullify ensures the valid flag for +// the sql.Null types are properly set. +// +// When a field within the User type is the zero +// value for the field, the valid flag is set to +// false causing it to be NULL in the database. +func (u *User) Nullify() *User { + if u == nil { + return nil + } + + // check if the ID field should be false + if u.ID.Int64 == 0 { + u.ID.Valid = false + } + + // check if the Name field should be false + if len(u.Name.String) == 0 { + u.Name.Valid = false + } + + // check if the RefreshToken field should be false + if len(u.RefreshToken.String) == 0 { + u.RefreshToken.Valid = false + } + + // check if the Token field should be false + if len(u.Token.String) == 0 { + u.Token.Valid = false + } + + return u +} + +// ToAPI converts the User type +// to an API User type. +func (u *User) ToAPI() *api.User { + user := new(api.User) + + user.SetID(u.ID.Int64) + user.SetName(u.Name.String) + user.SetRefreshToken(u.RefreshToken.String) + user.SetToken(u.Token.String) + user.SetActive(u.Active.Bool) + user.SetAdmin(u.Admin.Bool) + user.SetFavorites(u.Favorites) + user.SetDashboards(u.Dashboards) + + return user +} + +// Validate verifies the necessary fields for +// the User type are populated correctly. +func (u *User) Validate() error { + // verify the Name field is populated + if len(u.Name.String) == 0 { + return ErrEmptyUserName + } + + // verify the Token field is populated + if len(u.Token.String) == 0 { + return ErrEmptyUserToken + } + + // verify the Name field is valid + if !userRegex.MatchString(u.Name.String) { + return ErrInvalidUserName + } + + // calculate total size of favorites + total := 0 + for _, f := range u.Favorites { + total += len(f) + } + + // verify the Favorites field is within the database constraints + // len is to factor in number of comma separators included in the database field, + // removing 1 due to the last item not having an appended comma + if (total + len(u.Favorites) - 1) > constants.FavoritesMaxSize { + return ErrExceededFavoritesLimit + } + + // calculate totalDashboards size of dashboards + totalDashboards := 0 + for _, d := range u.Dashboards { + totalDashboards += len(d) + } + + // verify the Dashboards field is within the database constraints + // len is to factor in number of comma separators included in the database field, + // removing 1 due to the last item not having an appended comma + if (totalDashboards + len(u.Dashboards) - 1) > constants.FavoritesMaxSize { + return ErrExceededDashboardsLimit + } + + // ensure that all User string fields + // that can be returned as JSON are sanitized + // to avoid unsafe HTML content + u.Name = sql.NullString{String: util.Sanitize(u.Name.String), Valid: u.Name.Valid} + + // ensure that all Favorites are sanitized + // to avoid unsafe HTML content + for i, v := range u.Favorites { + u.Favorites[i] = util.Sanitize(v) + } + + return nil +} + +// UserFromAPI converts the API User type +// to a database User type. +func UserFromAPI(u *api.User) *User { + user := &User{ + ID: sql.NullInt64{Int64: u.GetID(), Valid: true}, + Name: sql.NullString{String: u.GetName(), Valid: true}, + RefreshToken: sql.NullString{String: u.GetRefreshToken(), Valid: true}, + Token: sql.NullString{String: u.GetToken(), Valid: true}, + Active: sql.NullBool{Bool: u.GetActive(), Valid: true}, + Admin: sql.NullBool{Bool: u.GetAdmin(), Valid: true}, + Favorites: pq.StringArray(u.GetFavorites()), + Dashboards: pq.StringArray(u.GetDashboards()), + } + + return user.Nullify() +} diff --git a/database/types/user_test.go b/database/types/user_test.go new file mode 100644 index 000000000..9edf57abf --- /dev/null +++ b/database/types/user_test.go @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "reflect" + "strconv" + "testing" + + api "github.com/go-vela/server/api/types" +) + +func TestTypes_User_Decrypt(t *testing.T) { + // setup types + key := "C639A572E14D5075C526FDDD43E4ECF6" + encrypted := testUser() + + err := encrypted.Encrypt(key) + if err != nil { + t.Errorf("unable to encrypt user: %v", err) + } + + // setup tests + tests := []struct { + failure bool + key string + user User + }{ + { + failure: false, + key: key, + user: *encrypted, + }, + { + failure: true, + key: "", + user: *encrypted, + }, + { + failure: true, + key: key, + user: *testUser(), + }, + } + + // run tests + for _, test := range tests { + err := test.user.Decrypt(test.key) + + if test.failure { + if err == nil { + t.Errorf("Decrypt should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Decrypt returned err: %v", err) + } + } +} + +func TestTypes_User_Encrypt(t *testing.T) { + // setup types + key := "C639A572E14D5075C526FDDD43E4ECF6" + + // setup tests + tests := []struct { + failure bool + key string + user *User + }{ + { + failure: false, + key: key, + user: testUser(), + }, + { + failure: true, + key: "", + user: testUser(), + }, + } + + // run tests + for _, test := range tests { + err := test.user.Encrypt(test.key) + + if test.failure { + if err == nil { + t.Errorf("Encrypt should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Encrypt returned err: %v", err) + } + } +} + +func TestTypes_User_Nullify(t *testing.T) { + // setup types + var u *User + + want := &User{ + ID: sql.NullInt64{Int64: 0, Valid: false}, + Name: sql.NullString{String: "", Valid: false}, + RefreshToken: sql.NullString{String: "", Valid: false}, + Token: sql.NullString{String: "", Valid: false}, + Active: sql.NullBool{Bool: false, Valid: false}, + Admin: sql.NullBool{Bool: false, Valid: false}, + } + + // setup tests + tests := []struct { + user *User + want *User + }{ + { + user: testUser(), + want: testUser(), + }, + { + user: u, + want: nil, + }, + { + user: new(User), + want: want, + }, + } + + // run tests + for _, test := range tests { + got := test.user.Nullify() + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Nullify is %v, want %v", got, test.want) + } + } +} + +func TestTypes_User_ToAPI(t *testing.T) { + // setup types + want := new(api.User) + + want.SetID(1) + want.SetName("octocat") + want.SetRefreshToken("superSecretRefreshToken") + want.SetToken("superSecretToken") + want.SetFavorites([]string{"github/octocat"}) + want.SetActive(true) + want.SetAdmin(false) + want.SetDashboards([]string{"45bcf19b-c151-4e2d-b8c6-80a62ba2eae7"}) + + // run test + got := testUser().ToAPI() + + if !reflect.DeepEqual(got, want) { + t.Errorf("ToAPI is %v, want %v", got, want) + } +} + +func TestTypes_User_Validate(t *testing.T) { + // setup tests + tests := []struct { + failure bool + user *User + }{ + { + failure: false, + user: testUser(), + }, + { // no name set for user + failure: true, + user: &User{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Token: sql.NullString{String: "superSecretToken", Valid: true}, + }, + }, + { // no token set for user + failure: true, + user: &User{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + }, + }, + { // invalid name set for user + failure: true, + user: &User{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "!@#$%^&*()", Valid: true}, + RefreshToken: sql.NullString{String: "superSecretRefreshToken", Valid: true}, + Token: sql.NullString{String: "superSecretToken", Valid: true}, + }, + }, + { // invalid favorites set for user + failure: true, + user: &User{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + Token: sql.NullString{String: "superSecretToken", Valid: true}, + Favorites: exceededField(), + }, + }, + { // invalid dashboards set for user + failure: true, + user: &User{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + Token: sql.NullString{String: "superSecretToken", Valid: true}, + Dashboards: exceededField(), + }, + }, + } + + // run tests + for _, test := range tests { + err := test.user.Validate() + + if test.failure { + if err == nil { + t.Errorf("Validate should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Validate returned err: %v", err) + } + } +} + +func TestFromAPI(t *testing.T) { + // setup types + u := new(api.User) + + u.SetID(1) + u.SetName("octocat") + u.SetRefreshToken("superSecretRefreshToken") + u.SetToken("superSecretToken") + u.SetFavorites([]string{"github/octocat"}) + u.SetActive(true) + u.SetAdmin(false) + u.SetDashboards([]string{"45bcf19b-c151-4e2d-b8c6-80a62ba2eae7"}) + + want := testUser() + + // run test + got := UserFromAPI(u) + + if !reflect.DeepEqual(got, want) { + t.Errorf("FromAPI is %v, want %v", got, want) + } +} + +// testUser is a test helper function to create a User +// type with all fields set to a fake value. +func testUser() *User { + return &User{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "octocat", Valid: true}, + RefreshToken: sql.NullString{String: "superSecretRefreshToken", Valid: true}, + Token: sql.NullString{String: "superSecretToken", Valid: true}, + Favorites: []string{"github/octocat"}, + Active: sql.NullBool{Bool: true, Valid: true}, + Admin: sql.NullBool{Bool: false, Valid: true}, + Dashboards: []string{"45bcf19b-c151-4e2d-b8c6-80a62ba2eae7"}, + } +} + +// exceededField returns a list of strings that exceed the maximum size of a field. +func exceededField() []string { + // initialize empty favorites + values := []string{} + + // add enough strings to exceed the character limit + for i := 0; i < 500; i++ { + // construct field + // use i to adhere to unique favorites + field := "github/octocat-" + strconv.Itoa(i) + + values = append(values, field) + } + + return values +} diff --git a/database/types/worker.go b/database/types/worker.go new file mode 100644 index 000000000..16062e65b --- /dev/null +++ b/database/types/worker.go @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "errors" + "fmt" + + "github.com/lib/pq" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/util" + "github.com/go-vela/types/constants" +) + +var ( + // ErrEmptyWorkerHost defines the error type when a + // Worker type has an empty Host field provided. + ErrEmptyWorkerHost = errors.New("empty worker hostname provided") + + // ErrEmptyWorkerAddress defines the error type when a + // Worker type has an empty Address field provided. + ErrEmptyWorkerAddress = errors.New("empty worker address provided") + + // ErrExceededRunningBuildIDsLimit defines the error type when a + // Worker type has RunningBuildIDs field provided that exceeds the database limit. + ErrExceededRunningBuildIDsLimit = errors.New("exceeded running build ids limit") +) + +// Worker is the database representation of a worker. +type Worker struct { + ID sql.NullInt64 `sql:"id"` + Hostname sql.NullString `sql:"hostname"` + Address sql.NullString `sql:"address"` + Routes pq.StringArray `sql:"routes" gorm:"type:varchar(1000)"` + Active sql.NullBool `sql:"active"` + Status sql.NullString `sql:"status"` + LastStatusUpdateAt sql.NullInt64 `sql:"last_status_update_at"` + RunningBuildIDs pq.StringArray `sql:"running_build_ids" gorm:"type:varchar(500)"` + LastBuildStartedAt sql.NullInt64 `sql:"last_build_started_at"` + LastBuildFinishedAt sql.NullInt64 `sql:"last_build_finished_at"` + LastCheckedIn sql.NullInt64 `sql:"last_checked_in"` + BuildLimit sql.NullInt64 `sql:"build_limit"` +} + +// Nullify ensures the valid flag for +// the sql.Null types are properly set. +// +// When a field within the Build type is the zero +// value for the field, the valid flag is set to +// false causing it to be NULL in the database. +func (w *Worker) Nullify() *Worker { + if w == nil { + return nil + } + + // check if the ID field should be false + if w.ID.Int64 == 0 { + w.ID.Valid = false + } + + // check if the Hostname field should be false + if len(w.Hostname.String) == 0 { + w.Hostname.Valid = false + } + + // check if the Address field should be false + if len(w.Address.String) == 0 { + w.Address.Valid = false + } + + // check if the Status field should be false + if len(w.Status.String) == 0 { + w.Status.Valid = false + } + + // check if the LastStatusUpdateAt field should be false + if w.LastStatusUpdateAt.Int64 == 0 { + w.LastStatusUpdateAt.Valid = false + } + + // check if the LastBuildStartedAt field should be false + if w.LastBuildStartedAt.Int64 == 0 { + w.LastBuildStartedAt.Valid = false + } + + // check if the LastBuildFinishedAt field should be false + if w.LastBuildFinishedAt.Int64 == 0 { + w.LastBuildFinishedAt.Valid = false + } + + // check if the LastCheckedIn field should be false + if w.LastCheckedIn.Int64 == 0 { + w.LastCheckedIn.Valid = false + } + + if w.BuildLimit.Int64 == 0 { + w.BuildLimit.Valid = false + } + + return w +} + +// ToAPI converts the Worker type +// to an API Worker type. +func (w *Worker) ToAPI(builds []*api.Build) *api.Worker { + worker := new(api.Worker) + + worker.SetID(w.ID.Int64) + worker.SetHostname(w.Hostname.String) + worker.SetAddress(w.Address.String) + worker.SetRoutes(w.Routes) + worker.SetActive(w.Active.Bool) + worker.SetStatus(w.Status.String) + worker.SetLastStatusUpdateAt(w.LastStatusUpdateAt.Int64) + worker.SetRunningBuilds(builds) + worker.SetLastBuildStartedAt(w.LastBuildStartedAt.Int64) + worker.SetLastBuildFinishedAt(w.LastBuildFinishedAt.Int64) + worker.SetLastCheckedIn(w.LastCheckedIn.Int64) + worker.SetBuildLimit(w.BuildLimit.Int64) + + return worker +} + +// Validate verifies the necessary fields for +// the Worker type are populated correctly. +func (w *Worker) Validate() error { + // verify the Host field is populated + if len(w.Hostname.String) == 0 { + return ErrEmptyWorkerHost + } + + // verify the Address field is populated + if len(w.Address.String) == 0 { + return ErrEmptyWorkerAddress + } + + // calculate total size of RunningBuildIds + total := 0 + for _, f := range w.RunningBuildIDs { + total += len(f) + } + + // verify the RunningBuildIds field is within the database constraints + // len is to factor in number of comma separators included in the database field, + // removing 1 due to the last item not having an appended comma + if (total + len(w.RunningBuildIDs) - 1) > constants.RunningBuildIDsMaxSize { + return ErrExceededRunningBuildIDsLimit + } + + // ensure that all Worker string fields + // that can be returned as JSON are sanitized + // to avoid unsafe HTML content + w.Hostname = sql.NullString{String: util.Sanitize(w.Hostname.String), Valid: w.Hostname.Valid} + w.Address = sql.NullString{String: util.Sanitize(w.Address.String), Valid: w.Address.Valid} + + // ensure that all Routes are sanitized + // to avoid unsafe HTML content + for i, v := range w.Routes { + w.Routes[i] = util.Sanitize(v) + } + + return nil +} + +// WorkerFromAPI converts the API worker type +// to a database worker type. +func WorkerFromAPI(w *api.Worker) *Worker { + var rBs []string + + for _, b := range w.GetRunningBuilds() { + rBs = append(rBs, fmt.Sprint(b.GetID())) + } + + worker := &Worker{ + ID: sql.NullInt64{Int64: w.GetID(), Valid: true}, + Hostname: sql.NullString{String: w.GetHostname(), Valid: true}, + Address: sql.NullString{String: w.GetAddress(), Valid: true}, + Routes: pq.StringArray(w.GetRoutes()), + Active: sql.NullBool{Bool: w.GetActive(), Valid: true}, + Status: sql.NullString{String: w.GetStatus(), Valid: true}, + LastStatusUpdateAt: sql.NullInt64{Int64: w.GetLastStatusUpdateAt(), Valid: true}, + RunningBuildIDs: pq.StringArray(rBs), + LastBuildStartedAt: sql.NullInt64{Int64: w.GetLastBuildStartedAt(), Valid: true}, + LastBuildFinishedAt: sql.NullInt64{Int64: w.GetLastBuildFinishedAt(), Valid: true}, + LastCheckedIn: sql.NullInt64{Int64: w.GetLastCheckedIn(), Valid: true}, + BuildLimit: sql.NullInt64{Int64: w.GetBuildLimit(), Valid: true}, + } + + return worker.Nullify() +} diff --git a/database/types/worker_test.go b/database/types/worker_test.go new file mode 100644 index 000000000..ec835d1f1 --- /dev/null +++ b/database/types/worker_test.go @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: Apache-2.0 + +package types + +import ( + "database/sql" + "reflect" + "strconv" + "testing" + + api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" +) + +func TestTypes_Worker_Nullify(t *testing.T) { + // setup types + var w *Worker + + want := &Worker{ + ID: sql.NullInt64{Int64: 0, Valid: false}, + Hostname: sql.NullString{String: "", Valid: false}, + Address: sql.NullString{String: "", Valid: false}, + Active: sql.NullBool{Bool: false, Valid: false}, + Status: sql.NullString{String: "", Valid: false}, + LastStatusUpdateAt: sql.NullInt64{Int64: 0, Valid: false}, + LastBuildStartedAt: sql.NullInt64{Int64: 0, Valid: false}, + LastBuildFinishedAt: sql.NullInt64{Int64: 0, Valid: false}, + LastCheckedIn: sql.NullInt64{Int64: 0, Valid: false}, + BuildLimit: sql.NullInt64{Int64: 0, Valid: false}, + } + + // setup tests + tests := []struct { + repo *Worker + want *Worker + }{ + { + repo: testWorker(), + want: testWorker(), + }, + { + repo: w, + want: nil, + }, + { + repo: new(Worker), + want: want, + }, + } + + // run tests + for _, test := range tests { + got := test.repo.Nullify() + + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Nullify is %v, want %v", got, test.want) + } + } +} + +func TestTypes_Worker_ToAPI(t *testing.T) { + // setup types + rB := testutils.APIBuild() + rB.SetID(1) + + want := new(api.Worker) + + want.SetID(1) + want.SetHostname("worker_0") + want.SetAddress("http://localhost:8080") + want.SetRoutes([]string{"vela"}) + want.SetActive(true) + want.SetStatus("available") + want.SetLastStatusUpdateAt(1563474077) + want.SetRunningBuilds([]*api.Build{rB}) + want.SetLastBuildStartedAt(1563474077) + want.SetLastBuildFinishedAt(1563474077) + want.SetLastCheckedIn(1563474077) + want.SetBuildLimit(2) + + // run test + got := testWorker().ToAPI(want.GetRunningBuilds()) + + if !reflect.DeepEqual(got, want) { + t.Errorf("ToAPI is %v, want %v", got, want) + } +} + +func TestTypes_Worker_Validate(t *testing.T) { + // setup tests + tests := []struct { + failure bool + worker *Worker + }{ + { + failure: false, + worker: testWorker(), + }, + { // no Hostname set for worker + failure: true, + worker: &Worker{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Address: sql.NullString{String: "http://localhost:8080", Valid: true}, + Active: sql.NullBool{Bool: true, Valid: true}, + LastCheckedIn: sql.NullInt64{Int64: 1563474077, Valid: true}, + }, + }, + { // no Address set for worker + failure: true, + worker: &Worker{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Hostname: sql.NullString{String: "worker_0", Valid: true}, + Active: sql.NullBool{Bool: true, Valid: true}, + LastCheckedIn: sql.NullInt64{Int64: 1563474077, Valid: true}, + }, + }, + { // invalid RunningBuildIDs set for worker + failure: true, + worker: &Worker{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Address: sql.NullString{String: "http://localhost:8080", Valid: true}, + Hostname: sql.NullString{String: "worker_0", Valid: true}, + Active: sql.NullBool{Bool: true, Valid: true}, + RunningBuildIDs: exceededRunningBuildIDs(), + LastCheckedIn: sql.NullInt64{Int64: 1563474077, Valid: true}, + }, + }, + } + + // run tests + for _, test := range tests { + err := test.worker.Validate() + + if test.failure { + if err == nil { + t.Errorf("Validate should have returned err") + } + + continue + } + + if err != nil { + t.Errorf("Validate returned err: %v", err) + } + } +} + +func TestTypes_Worker_WorkerFromAPI(t *testing.T) { + // setup types + rB := testutils.APIBuild() + rB.SetID(1) + + w := new(api.Worker) + + w.SetID(1) + w.SetHostname("worker_0") + w.SetAddress("http://localhost:8080") + w.SetRoutes([]string{"vela"}) + w.SetActive(true) + w.SetStatus("available") + w.SetLastStatusUpdateAt(1563474077) + w.SetRunningBuilds([]*api.Build{rB}) + w.SetLastBuildStartedAt(1563474077) + w.SetLastBuildFinishedAt(1563474077) + w.SetLastCheckedIn(1563474077) + w.SetBuildLimit(2) + + want := testWorker() + + // run test + got := WorkerFromAPI(w) + + if !reflect.DeepEqual(got, want) { + t.Errorf("WorkerFromLibrary is %v, want %v", got, want) + } +} + +// testWorker is a test helper function to create a Worker +// type with all fields set to a fake value. +func testWorker() *Worker { + return &Worker{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Hostname: sql.NullString{String: "worker_0", Valid: true}, + Address: sql.NullString{String: "http://localhost:8080", Valid: true}, + Routes: []string{"vela"}, + Active: sql.NullBool{Bool: true, Valid: true}, + Status: sql.NullString{String: "available", Valid: true}, + LastStatusUpdateAt: sql.NullInt64{Int64: 1563474077, Valid: true}, + RunningBuildIDs: []string{"1"}, + LastBuildStartedAt: sql.NullInt64{Int64: 1563474077, Valid: true}, + LastBuildFinishedAt: sql.NullInt64{Int64: 1563474077, Valid: true}, + LastCheckedIn: sql.NullInt64{Int64: 1563474077, Valid: true}, + BuildLimit: sql.NullInt64{Int64: 2, Valid: true}, + } +} + +// exceededRunningBuildIDs returns a list of valid running builds that exceed the maximum size. +func exceededRunningBuildIDs() []string { + // initialize empty runningBuildIDs + runningBuildIDs := []string{} + + // add enough build ids to exceed the character limit + for i := 0; i < 50; i++ { + // construct runningBuildID + // use i to adhere to unique runningBuildIDs + runningBuildID := "1234567890-" + strconv.Itoa(i) + + runningBuildIDs = append(runningBuildIDs, runningBuildID) + } + + return runningBuildIDs +} diff --git a/database/user/count_test.go b/database/user/count_test.go index fd88de828..ebeb32181 100644 --- a/database/user/count_test.go +++ b/database/user/count_test.go @@ -8,16 +8,18 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestUser_Engine_CountUsers(t *testing.T) { // setup types - _userOne := testAPIUser() + _userOne := testutils.APIUser() _userOne.SetID(1) _userOne.SetName("foo") _userOne.SetToken("bar") - _userTwo := testAPIUser() + _userTwo := testutils.APIUser() _userTwo.SetID(2) _userTwo.SetName("baz") _userTwo.SetToken("bar") diff --git a/database/user/create.go b/database/user/create.go index cd6b9a761..b8cb1e59d 100644 --- a/database/user/create.go +++ b/database/user/create.go @@ -10,6 +10,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -20,7 +21,7 @@ func (e *engine) CreateUser(ctx context.Context, u *api.User) (*api.User, error) }).Tracef("creating user %s in the database", u.GetName()) // cast the API type to database type - user := FromAPI(u) + user := types.UserFromAPI(u) // validate the necessary fields are populated // diff --git a/database/user/create_test.go b/database/user/create_test.go index 988cac912..97dea7f3e 100644 --- a/database/user/create_test.go +++ b/database/user/create_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestUser_Engine_CreateUser(t *testing.T) { // setup types - _user := testAPIUser() + _user := testutils.APIUser() _user.SetID(1) _user.SetName("foo") _user.SetToken("bar") diff --git a/database/user/delete.go b/database/user/delete.go index 848e08ca5..b7a7be169 100644 --- a/database/user/delete.go +++ b/database/user/delete.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -18,7 +19,7 @@ func (e *engine) DeleteUser(ctx context.Context, u *api.User) error { }).Tracef("deleting user %s from the database", u.GetName()) // cast the API type to database type - user := FromAPI(u) + user := types.UserFromAPI(u) // send query to the database return e.client. diff --git a/database/user/delete_test.go b/database/user/delete_test.go index 6926929d9..2a282d856 100644 --- a/database/user/delete_test.go +++ b/database/user/delete_test.go @@ -7,11 +7,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestUser_Engine_DeleteUser(t *testing.T) { // setup types - _user := testAPIUser() + _user := testutils.APIUser() _user.SetID(1) _user.SetName("foo") _user.SetToken("bar") diff --git a/database/user/get.go b/database/user/get.go index 90e16a46e..e0f8d45d9 100644 --- a/database/user/get.go +++ b/database/user/get.go @@ -6,6 +6,7 @@ import ( "context" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -14,7 +15,7 @@ func (e *engine) GetUser(ctx context.Context, id int64) (*api.User, error) { e.logger.Tracef("getting user %d from the database", id) // variable to store query results - u := new(User) + u := new(types.User) // send query to the database and store result in variable err := e.client. diff --git a/database/user/get_name.go b/database/user/get_name.go index 87dd13bea..f74c07166 100644 --- a/database/user/get_name.go +++ b/database/user/get_name.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -18,7 +19,7 @@ func (e *engine) GetUserForName(ctx context.Context, name string) (*api.User, er }).Tracef("getting user %s from the database", name) // variable to store query results - u := new(User) + u := new(types.User) // send query to the database and store result in variable err := e.client. diff --git a/database/user/get_name_test.go b/database/user/get_name_test.go index 72a9c1e08..b4bbe7f74 100644 --- a/database/user/get_name_test.go +++ b/database/user/get_name_test.go @@ -10,11 +10,12 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestUser_Engine_GetUserForName(t *testing.T) { // setup types - _user := testAPIUser() + _user := testutils.APIUser() _user.SetID(1) _user.SetName("foo") _user.SetToken("bar") diff --git a/database/user/get_test.go b/database/user/get_test.go index 213da30f8..3981799f3 100644 --- a/database/user/get_test.go +++ b/database/user/get_test.go @@ -10,11 +10,12 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestUser_Engine_GetUser(t *testing.T) { // setup types - _user := testAPIUser() + _user := testutils.APIUser() _user.SetID(1) _user.SetName("foo") _user.SetToken("bar") diff --git a/database/user/list.go b/database/user/list.go index 0fed81070..29b53f7f0 100644 --- a/database/user/list.go +++ b/database/user/list.go @@ -6,6 +6,7 @@ import ( "context" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -15,7 +16,7 @@ func (e *engine) ListUsers(ctx context.Context) ([]*api.User, error) { // variables to store query results and return value count := int64(0) - u := new([]User) + u := new([]types.User) users := []*api.User{} // count the results diff --git a/database/user/list_lite.go b/database/user/list_lite.go index 809b9c83f..d3ca1c49a 100644 --- a/database/user/list_lite.go +++ b/database/user/list_lite.go @@ -6,6 +6,7 @@ import ( "context" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -17,7 +18,7 @@ func (e *engine) ListLiteUsers(ctx context.Context, page, perPage int) ([]*api.U // variables to store query results and return values count := int64(0) - u := new([]User) + u := new([]types.User) users := []*api.User{} // count the results diff --git a/database/user/list_lite_test.go b/database/user/list_lite_test.go index 6f2888e50..31a4b1f0f 100644 --- a/database/user/list_lite_test.go +++ b/database/user/list_lite_test.go @@ -10,18 +10,19 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestUser_Engine_ListLiteUsers(t *testing.T) { // setup types - _userOne := testAPIUser() + _userOne := testutils.APIUser() _userOne.SetID(1) _userOne.SetName("foo") _userOne.SetToken("bar") _userOne.SetFavorites([]string{}) _userOne.SetDashboards([]string{}) - _userTwo := testAPIUser() + _userTwo := testutils.APIUser() _userTwo.SetID(2) _userTwo.SetName("baz") _userTwo.SetToken("bar") diff --git a/database/user/list_test.go b/database/user/list_test.go index 01a847ea8..ce2e7b3f7 100644 --- a/database/user/list_test.go +++ b/database/user/list_test.go @@ -10,18 +10,19 @@ import ( "github.com/DATA-DOG/go-sqlmock" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/testutils" ) func TestUser_Engine_ListUsers(t *testing.T) { // setup types - _userOne := testAPIUser() + _userOne := testutils.APIUser() _userOne.SetID(1) _userOne.SetName("foo") _userOne.SetToken("bar") _userOne.SetFavorites([]string{}) _userOne.SetDashboards([]string{}) - _userTwo := testAPIUser() + _userTwo := testutils.APIUser() _userTwo.SetID(2) _userTwo.SetName("baz") _userTwo.SetToken("bar") diff --git a/database/user/update.go b/database/user/update.go index 2779e6497..b785352eb 100644 --- a/database/user/update.go +++ b/database/user/update.go @@ -10,6 +10,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -20,7 +21,7 @@ func (e *engine) UpdateUser(ctx context.Context, u *api.User) (*api.User, error) }).Tracef("updating user %s in the database", u.GetName()) // cast the library type to database type - user := FromAPI(u) + user := types.UserFromAPI(u) // validate the necessary fields are populated err := user.Validate() diff --git a/database/user/update_test.go b/database/user/update_test.go index 5fbb7ed8b..8170c6375 100644 --- a/database/user/update_test.go +++ b/database/user/update_test.go @@ -8,11 +8,13 @@ import ( "testing" "github.com/DATA-DOG/go-sqlmock" + + "github.com/go-vela/server/database/testutils" ) func TestUser_Engine_UpdateUser(t *testing.T) { // setup types - _user := testAPIUser() + _user := testutils.APIUser() _user.SetID(1) _user.SetName("foo") _user.SetToken("bar") diff --git a/database/user/user.go b/database/user/user.go index a29295cbb..23948bfb3 100644 --- a/database/user/user.go +++ b/database/user/user.go @@ -4,51 +4,14 @@ package user import ( "context" - "database/sql" - "encoding/base64" - "errors" "fmt" - "regexp" - "github.com/lib/pq" "github.com/sirupsen/logrus" "gorm.io/gorm" - api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/util" "github.com/go-vela/types/constants" ) -var ( - // userRegex defines the regex pattern for validating - // the Name field for the User type. - userRegex = regexp.MustCompile("^[a-zA-Z0-9_-]{0,38}$") - - // ErrEmptyUserName defines the error type when a - // User type has an empty Name field provided. - ErrEmptyUserName = errors.New("empty user name provided") - - // ErrEmptyUserRefreshToken defines the error type when a - // User type has an empty RefreshToken field provided. - ErrEmptyUserRefreshToken = errors.New("empty user refresh token provided") - - // ErrEmptyUserToken defines the error type when a - // User type has an empty Token field provided. - ErrEmptyUserToken = errors.New("empty user token provided") - - // ErrInvalidUserName defines the error type when a - // User type has an invalid Name field provided. - ErrInvalidUserName = errors.New("invalid user name provided") - - // ErrExceededFavoritesLimit defines the error type when a - // User type has Favorites field provided that exceeds the database limit. - ErrExceededFavoritesLimit = errors.New("exceeded favorites limit") - - // ErrExceededDashboardsLimit defines the error type when a - // User type has Dashboards field provided that exceeds the database limit. - ErrExceededDashboardsLimit = errors.New("exceeded dashboards limit") -) - type ( // config represents the settings required to create the engine that implements the UserInterface interface. config struct { @@ -75,18 +38,6 @@ type ( // https://pkg.go.dev/github.com/sirupsen/logrus#Entry logger *logrus.Entry } - - // User is the database representation of a user. - User struct { - ID sql.NullInt64 `sql:"id"` - Name sql.NullString `sql:"name"` - RefreshToken sql.NullString `sql:"refresh_token"` - Token sql.NullString `sql:"token"` - Favorites pq.StringArray `sql:"favorites" gorm:"type:varchar(5000)"` - Active sql.NullBool `sql:"active"` - Admin sql.NullBool `sql:"admin"` - Dashboards pq.StringArray `sql:"dashboards" gorm:"type:varchar(5000)"` - } ) // New creates and returns a Vela service for integrating with users in the database. @@ -130,206 +81,3 @@ func New(opts ...EngineOpt) (*engine, error) { return e, nil } - -// Decrypt will manipulate the existing user tokens by -// base64 decoding them. Then, a AES-256 cipher -// block is created from the encryption key in order to -// decrypt the base64 decoded user tokens. -func (u *User) Decrypt(key string) error { - // base64 decode the encrypted user token - decoded, err := base64.StdEncoding.DecodeString(u.Token.String) - if err != nil { - return err - } - - // decrypt the base64 decoded user token - decrypted, err := util.Decrypt(key, decoded) - if err != nil { - return err - } - - // set the decrypted user token - u.Token = sql.NullString{ - String: string(decrypted), - Valid: true, - } - - // base64 decode the encrypted user refresh token - decoded, err = base64.StdEncoding.DecodeString(u.RefreshToken.String) - if err != nil { - return err - } - - // decrypt the base64 decoded user refresh token - decrypted, err = util.Decrypt(key, decoded) - if err != nil { - return err - } - - // set the decrypted user refresh token - u.RefreshToken = sql.NullString{ - String: string(decrypted), - Valid: true, - } - - return nil -} - -// Encrypt will manipulate the existing user tokens by -// creating a AES-256 cipher block from the encryption -// key in order to encrypt the user tokens. Then, the -// user tokens are base64 encoded for transport across -// network boundaries. -func (u *User) Encrypt(key string) error { - // encrypt the user token - encrypted, err := util.Encrypt(key, []byte(u.Token.String)) - if err != nil { - return err - } - - // base64 encode the encrypted user token to make it network safe - u.Token = sql.NullString{ - String: base64.StdEncoding.EncodeToString(encrypted), - Valid: true, - } - - // encrypt the user refresh token - encrypted, err = util.Encrypt(key, []byte(u.RefreshToken.String)) - if err != nil { - return err - } - - // base64 encode the encrypted user refresh token to make it network safe - u.RefreshToken = sql.NullString{ - String: base64.StdEncoding.EncodeToString(encrypted), - Valid: true, - } - - return nil -} - -// Nullify ensures the valid flag for -// the sql.Null types are properly set. -// -// When a field within the User type is the zero -// value for the field, the valid flag is set to -// false causing it to be NULL in the database. -func (u *User) Nullify() *User { - if u == nil { - return nil - } - - // check if the ID field should be false - if u.ID.Int64 == 0 { - u.ID.Valid = false - } - - // check if the Name field should be false - if len(u.Name.String) == 0 { - u.Name.Valid = false - } - - // check if the RefreshToken field should be false - if len(u.RefreshToken.String) == 0 { - u.RefreshToken.Valid = false - } - - // check if the Token field should be false - if len(u.Token.String) == 0 { - u.Token.Valid = false - } - - return u -} - -// ToAPI converts the User type -// to an API User type. -func (u *User) ToAPI() *api.User { - user := new(api.User) - - user.SetID(u.ID.Int64) - user.SetName(u.Name.String) - user.SetRefreshToken(u.RefreshToken.String) - user.SetToken(u.Token.String) - user.SetActive(u.Active.Bool) - user.SetAdmin(u.Admin.Bool) - user.SetFavorites(u.Favorites) - user.SetDashboards(u.Dashboards) - - return user -} - -// Validate verifies the necessary fields for -// the User type are populated correctly. -func (u *User) Validate() error { - // verify the Name field is populated - if len(u.Name.String) == 0 { - return ErrEmptyUserName - } - - // verify the Token field is populated - if len(u.Token.String) == 0 { - return ErrEmptyUserToken - } - - // verify the Name field is valid - if !userRegex.MatchString(u.Name.String) { - return ErrInvalidUserName - } - - // calculate totalFavorites size of favorites - totalFavorites := 0 - for _, f := range u.Favorites { - totalFavorites += len(f) - } - - // verify the Favorites field is within the database constraints - // len is to factor in number of comma separators included in the database field, - // removing 1 due to the last item not having an appended comma - if (totalFavorites + len(u.Favorites) - 1) > constants.FavoritesMaxSize { - return ErrExceededFavoritesLimit - } - - // calculate totalDashboards size of dashboards - totalDashboards := 0 - for _, d := range u.Dashboards { - totalDashboards += len(d) - } - - // verify the Dashboards field is within the database constraints - // len is to factor in number of comma separators included in the database field, - // removing 1 due to the last item not having an appended comma - if (totalDashboards + len(u.Dashboards) - 1) > constants.FavoritesMaxSize { - return ErrExceededDashboardsLimit - } - - // ensure that all User string fields - // that can be returned as JSON are sanitized - // to avoid unsafe HTML content - u.Name = sql.NullString{String: util.Sanitize(u.Name.String), Valid: u.Name.Valid} - - // ensure that all Favorites are sanitized - // to avoid unsafe HTML content - for i, v := range u.Favorites { - u.Favorites[i] = util.Sanitize(v) - } - - return nil -} - -// FromAPI converts the API User type -// to a database User type. -func FromAPI(u *api.User) *User { - user := &User{ - ID: sql.NullInt64{Int64: u.GetID(), Valid: true}, - Name: sql.NullString{String: u.GetName(), Valid: true}, - RefreshToken: sql.NullString{String: u.GetRefreshToken(), Valid: true}, - Token: sql.NullString{String: u.GetToken(), Valid: true}, - Active: sql.NullBool{Bool: u.GetActive(), Valid: true}, - Admin: sql.NullBool{Bool: u.GetAdmin(), Valid: true}, - Favorites: pq.StringArray(u.GetFavorites()), - Dashboards: pq.StringArray(u.GetDashboards()), - } - - return user.Nullify() -} diff --git a/database/user/user_test.go b/database/user/user_test.go index 287ee9508..8e33e6e62 100644 --- a/database/user/user_test.go +++ b/database/user/user_test.go @@ -3,10 +3,8 @@ package user import ( - "database/sql" "database/sql/driver" "reflect" - "strconv" "testing" "github.com/DATA-DOG/go-sqlmock" @@ -14,8 +12,6 @@ import ( "gorm.io/driver/postgres" "gorm.io/driver/sqlite" "gorm.io/gorm" - - api "github.com/go-vela/server/api/types" ) func TestUser_New(t *testing.T) { @@ -172,21 +168,6 @@ func testSqlite(t *testing.T) *engine { return _engine } -// testAPIUser is a test helper function to create an API -// User type with all fields set to their zero values. -func testAPIUser() *api.User { - return &api.User{ - ID: new(int64), - Name: new(string), - RefreshToken: new(string), - Token: new(string), - Favorites: new([]string), - Active: new(bool), - Admin: new(bool), - Dashboards: new([]string), - } -} - // This will be used with the github.com/DATA-DOG/go-sqlmock library to compare values // that are otherwise not easily compared. These typically would be values generated // before adding or updating them in the database. @@ -198,283 +179,3 @@ type AnyArgument struct{} func (a AnyArgument) Match(_ driver.Value) bool { return true } - -func TestUser_Decrypt(t *testing.T) { - // setup types - key := "C639A572E14D5075C526FDDD43E4ECF6" - encrypted := testUser() - - err := encrypted.Encrypt(key) - if err != nil { - t.Errorf("unable to encrypt user: %v", err) - } - - // setup tests - tests := []struct { - failure bool - key string - user User - }{ - { - failure: false, - key: key, - user: *encrypted, - }, - { - failure: true, - key: "", - user: *encrypted, - }, - { - failure: true, - key: key, - user: *testUser(), - }, - } - - // run tests - for _, test := range tests { - err := test.user.Decrypt(test.key) - - if test.failure { - if err == nil { - t.Errorf("Decrypt should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Decrypt returned err: %v", err) - } - } -} - -func TestUser_Encrypt(t *testing.T) { - // setup types - key := "C639A572E14D5075C526FDDD43E4ECF6" - - // setup tests - tests := []struct { - failure bool - key string - user *User - }{ - { - failure: false, - key: key, - user: testUser(), - }, - { - failure: true, - key: "", - user: testUser(), - }, - } - - // run tests - for _, test := range tests { - err := test.user.Encrypt(test.key) - - if test.failure { - if err == nil { - t.Errorf("Encrypt should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Encrypt returned err: %v", err) - } - } -} - -func TestUser_Nullify(t *testing.T) { - // setup types - var u *User - - want := &User{ - ID: sql.NullInt64{Int64: 0, Valid: false}, - Name: sql.NullString{String: "", Valid: false}, - RefreshToken: sql.NullString{String: "", Valid: false}, - Token: sql.NullString{String: "", Valid: false}, - Active: sql.NullBool{Bool: false, Valid: false}, - Admin: sql.NullBool{Bool: false, Valid: false}, - } - - // setup tests - tests := []struct { - user *User - want *User - }{ - { - user: testUser(), - want: testUser(), - }, - { - user: u, - want: nil, - }, - { - user: new(User), - want: want, - }, - } - - // run tests - for _, test := range tests { - got := test.user.Nullify() - - if !reflect.DeepEqual(got, test.want) { - t.Errorf("Nullify is %v, want %v", got, test.want) - } - } -} - -func TestUser_ToAPI(t *testing.T) { - // setup types - want := new(api.User) - - want.SetID(1) - want.SetName("octocat") - want.SetRefreshToken("superSecretRefreshToken") - want.SetToken("superSecretToken") - want.SetFavorites([]string{"github/octocat"}) - want.SetActive(true) - want.SetAdmin(false) - want.SetDashboards([]string{"45bcf19b-c151-4e2d-b8c6-80a62ba2eae7"}) - - // run test - got := testUser().ToAPI() - - if !reflect.DeepEqual(got, want) { - t.Errorf("ToAPI is %v, want %v", got, want) - } -} - -func TestUser_Validate(t *testing.T) { - // setup tests - tests := []struct { - failure bool - user *User - }{ - { - failure: false, - user: testUser(), - }, - { // no name set for user - failure: true, - user: &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Token: sql.NullString{String: "superSecretToken", Valid: true}, - }, - }, - { // no token set for user - failure: true, - user: &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - }, - }, - { // invalid name set for user - failure: true, - user: &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Name: sql.NullString{String: "!@#$%^&*()", Valid: true}, - RefreshToken: sql.NullString{String: "superSecretRefreshToken", Valid: true}, - Token: sql.NullString{String: "superSecretToken", Valid: true}, - }, - }, - { // invalid favorites set for user - failure: true, - user: &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - Token: sql.NullString{String: "superSecretToken", Valid: true}, - Favorites: exceededField(), - }, - }, - { // invalid dashboards set for user - failure: true, - user: &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - Token: sql.NullString{String: "superSecretToken", Valid: true}, - Dashboards: exceededField(), - }, - }, - } - - // run tests - for _, test := range tests { - err := test.user.Validate() - - if test.failure { - if err == nil { - t.Errorf("Validate should have returned err") - } - - continue - } - - if err != nil { - t.Errorf("Validate returned err: %v", err) - } - } -} - -func TestFromAPI(t *testing.T) { - // setup types - u := new(api.User) - - u.SetID(1) - u.SetName("octocat") - u.SetRefreshToken("superSecretRefreshToken") - u.SetToken("superSecretToken") - u.SetFavorites([]string{"github/octocat"}) - u.SetActive(true) - u.SetAdmin(false) - u.SetDashboards([]string{"45bcf19b-c151-4e2d-b8c6-80a62ba2eae7"}) - - want := testUser() - - // run test - got := FromAPI(u) - - if !reflect.DeepEqual(got, want) { - t.Errorf("FromAPI is %v, want %v", got, want) - } -} - -// testUser is a test helper function to create a User -// type with all fields set to a fake value. -func testUser() *User { - return &User{ - ID: sql.NullInt64{Int64: 1, Valid: true}, - Name: sql.NullString{String: "octocat", Valid: true}, - RefreshToken: sql.NullString{String: "superSecretRefreshToken", Valid: true}, - Token: sql.NullString{String: "superSecretToken", Valid: true}, - Favorites: []string{"github/octocat"}, - Active: sql.NullBool{Bool: true, Valid: true}, - Admin: sql.NullBool{Bool: false, Valid: true}, - Dashboards: []string{"45bcf19b-c151-4e2d-b8c6-80a62ba2eae7"}, - } -} - -// exceededField returns a list of strings that exceed the maximum size of a field. -func exceededField() []string { - // initialize empty favorites - values := []string{} - - // add enough strings to exceed the character limit - for i := 0; i < 500; i++ { - // construct field - // use i to adhere to unique favorites - field := "github/octocat-" + strconv.Itoa(i) - - values = append(values, field) - } - - return values -} diff --git a/database/worker/create.go b/database/worker/create.go index 43232a71d..c566ecd0e 100644 --- a/database/worker/create.go +++ b/database/worker/create.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -20,7 +21,7 @@ func (e *engine) CreateWorker(ctx context.Context, w *api.Worker) (*api.Worker, // cast the library type to database type // // https://pkg.go.dev/github.com/go-vela/types/database#WorkerFromLibrary - worker := FromAPI(w) + worker := types.WorkerFromAPI(w) // validate the necessary fields are populated // diff --git a/database/worker/delete.go b/database/worker/delete.go index a20e46487..4972efc98 100644 --- a/database/worker/delete.go +++ b/database/worker/delete.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -20,7 +21,7 @@ func (e *engine) DeleteWorker(ctx context.Context, w *api.Worker) error { // cast the library type to database type // // https://pkg.go.dev/github.com/go-vela/types/database#WorkerFromLibrary - worker := FromAPI(w) + worker := types.WorkerFromAPI(w) // send query to the database return e.client. diff --git a/database/worker/get.go b/database/worker/get.go index 7531fd05a..7aca60b76 100644 --- a/database/worker/get.go +++ b/database/worker/get.go @@ -6,6 +6,7 @@ import ( "context" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -14,7 +15,7 @@ func (e *engine) GetWorker(ctx context.Context, id int64) (*api.Worker, error) { e.logger.Tracef("getting worker %d from the database", id) // variable to store query results - w := new(Worker) + w := new(types.Worker) // send query to the database and store result in variable err := e.client. diff --git a/database/worker/get_hostname.go b/database/worker/get_hostname.go index 6f046f8dd..ec37b9200 100644 --- a/database/worker/get_hostname.go +++ b/database/worker/get_hostname.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -18,7 +19,7 @@ func (e *engine) GetWorkerForHostname(ctx context.Context, hostname string) (*ap }).Tracef("getting worker %s from the database", hostname) // variable to store query results - w := new(Worker) + w := new(types.Worker) // send query to the database and store result in variable err := e.client. diff --git a/database/worker/list.go b/database/worker/list.go index daa9a7e06..a8adc1a79 100644 --- a/database/worker/list.go +++ b/database/worker/list.go @@ -8,6 +8,7 @@ import ( "strconv" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -16,7 +17,7 @@ func (e *engine) ListWorkers(ctx context.Context, active string, before, after i e.logger.Trace("listing all workers from the database") // variables to store query results and return value - results := new([]Worker) + results := new([]types.Worker) workers := []*api.Worker{} // build query with checked in constraints diff --git a/database/worker/update.go b/database/worker/update.go index 4626ce746..996d0c0af 100644 --- a/database/worker/update.go +++ b/database/worker/update.go @@ -8,6 +8,7 @@ import ( "github.com/sirupsen/logrus" api "github.com/go-vela/server/api/types" + "github.com/go-vela/server/database/types" "github.com/go-vela/types/constants" ) @@ -20,7 +21,7 @@ func (e *engine) UpdateWorker(ctx context.Context, w *api.Worker) (*api.Worker, // cast the library type to database type // // https://pkg.go.dev/github.com/go-vela/types/database#WorkerFromLibrary - worker := FromAPI(w) + worker := types.WorkerFromAPI(w) // validate the necessary fields are populated // diff --git a/database/worker/worker.go b/database/worker/worker.go index f05c7198c..18e4d90d9 100644 --- a/database/worker/worker.go +++ b/database/worker/worker.go @@ -4,33 +4,14 @@ package worker import ( "context" - "database/sql" - "errors" "fmt" "strconv" - "github.com/lib/pq" "github.com/sirupsen/logrus" "gorm.io/gorm" api "github.com/go-vela/server/api/types" - "github.com/go-vela/server/util" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" -) - -var ( - // ErrEmptyWorkerHost defines the error type when a - // Worker type has an empty Host field provided. - ErrEmptyWorkerHost = errors.New("empty worker hostname provided") - - // ErrEmptyWorkerAddress defines the error type when a - // Worker type has an empty Address field provided. - ErrEmptyWorkerAddress = errors.New("empty worker address provided") - - // ErrExceededRunningBuildIDsLimit defines the error type when a - // Worker type has RunningBuildIDs field provided that exceeds the database limit. - ErrExceededRunningBuildIDsLimit = errors.New("exceeded running build ids limit") ) type ( @@ -57,22 +38,6 @@ type ( // https://pkg.go.dev/github.com/sirupsen/logrus#Entry logger *logrus.Entry } - - // Worker is the database representation of a worker. - Worker struct { - ID sql.NullInt64 `sql:"id"` - Hostname sql.NullString `sql:"hostname"` - Address sql.NullString `sql:"address"` - Routes pq.StringArray `sql:"routes" gorm:"type:varchar(1000)"` - Active sql.NullBool `sql:"active"` - Status sql.NullString `sql:"status"` - LastStatusUpdateAt sql.NullInt64 `sql:"last_status_update_at"` - RunningBuildIDs pq.StringArray `sql:"running_build_ids" gorm:"type:varchar(500)"` - LastBuildStartedAt sql.NullInt64 `sql:"last_build_started_at"` - LastBuildFinishedAt sql.NullInt64 `sql:"last_build_finished_at"` - LastCheckedIn sql.NullInt64 `sql:"last_checked_in"` - BuildLimit sql.NullInt64 `sql:"build_limit"` - } ) // New creates and returns a Vela service for integrating with workers in the database. @@ -117,157 +82,10 @@ func New(opts ...EngineOpt) (*engine, error) { return e, nil } -// Nullify ensures the valid flag for -// the sql.Null types are properly set. -// -// When a field within the Build type is the zero -// value for the field, the valid flag is set to -// false causing it to be NULL in the database. -func (w *Worker) Nullify() *Worker { - if w == nil { - return nil - } - - // check if the ID field should be false - if w.ID.Int64 == 0 { - w.ID.Valid = false - } - - // check if the Hostname field should be false - if len(w.Hostname.String) == 0 { - w.Hostname.Valid = false - } - - // check if the Address field should be false - if len(w.Address.String) == 0 { - w.Address.Valid = false - } - - // check if the Status field should be false - if len(w.Status.String) == 0 { - w.Status.Valid = false - } - - // check if the LastStatusUpdateAt field should be false - if w.LastStatusUpdateAt.Int64 == 0 { - w.LastStatusUpdateAt.Valid = false - } - - // check if the LastBuildStartedAt field should be false - if w.LastBuildStartedAt.Int64 == 0 { - w.LastBuildStartedAt.Valid = false - } - - // check if the LastBuildFinishedAt field should be false - if w.LastBuildFinishedAt.Int64 == 0 { - w.LastBuildFinishedAt.Valid = false - } - - // check if the LastCheckedIn field should be false - if w.LastCheckedIn.Int64 == 0 { - w.LastCheckedIn.Valid = false - } - - if w.BuildLimit.Int64 == 0 { - w.BuildLimit.Valid = false - } - - return w -} - -// ToAPI converts the Worker type -// to an API Worker type. -func (w *Worker) ToAPI(builds []*library.Build) *api.Worker { - worker := new(api.Worker) - - worker.SetID(w.ID.Int64) - worker.SetHostname(w.Hostname.String) - worker.SetAddress(w.Address.String) - worker.SetRoutes(w.Routes) - worker.SetActive(w.Active.Bool) - worker.SetStatus(w.Status.String) - worker.SetLastStatusUpdateAt(w.LastStatusUpdateAt.Int64) - worker.SetRunningBuilds(builds) - worker.SetLastBuildStartedAt(w.LastBuildStartedAt.Int64) - worker.SetLastBuildFinishedAt(w.LastBuildFinishedAt.Int64) - worker.SetLastCheckedIn(w.LastCheckedIn.Int64) - worker.SetBuildLimit(w.BuildLimit.Int64) - - return worker -} - -// Validate verifies the necessary fields for -// the Worker type are populated correctly. -func (w *Worker) Validate() error { - // verify the Host field is populated - if len(w.Hostname.String) == 0 { - return ErrEmptyWorkerHost - } - - // verify the Address field is populated - if len(w.Address.String) == 0 { - return ErrEmptyWorkerAddress - } - - // calculate total size of RunningBuildIds - total := 0 - for _, f := range w.RunningBuildIDs { - total += len(f) - } - - // verify the RunningBuildIds field is within the database constraints - // len is to factor in number of comma separators included in the database field, - // removing 1 due to the last item not having an appended comma - if (total + len(w.RunningBuildIDs) - 1) > constants.RunningBuildIDsMaxSize { - return ErrExceededRunningBuildIDsLimit - } - - // ensure that all Worker string fields - // that can be returned as JSON are sanitized - // to avoid unsafe HTML content - w.Hostname = sql.NullString{String: util.Sanitize(w.Hostname.String), Valid: w.Hostname.Valid} - w.Address = sql.NullString{String: util.Sanitize(w.Address.String), Valid: w.Address.Valid} - - // ensure that all Routes are sanitized - // to avoid unsafe HTML content - for i, v := range w.Routes { - w.Routes[i] = util.Sanitize(v) - } - - return nil -} - -// FromAPI converts the API worker type -// to a database worker type. -func FromAPI(w *api.Worker) *Worker { - var rBs []string - - for _, b := range w.GetRunningBuilds() { - rBs = append(rBs, fmt.Sprint(b.GetID())) - } - - worker := &Worker{ - ID: sql.NullInt64{Int64: w.GetID(), Valid: true}, - Hostname: sql.NullString{String: w.GetHostname(), Valid: true}, - Address: sql.NullString{String: w.GetAddress(), Valid: true}, - Routes: pq.StringArray(w.GetRoutes()), - Active: sql.NullBool{Bool: w.GetActive(), Valid: true}, - Status: sql.NullString{String: w.GetStatus(), Valid: true}, - LastStatusUpdateAt: sql.NullInt64{Int64: w.GetLastStatusUpdateAt(), Valid: true}, - RunningBuildIDs: pq.StringArray(rBs), - LastBuildStartedAt: sql.NullInt64{Int64: w.GetLastBuildStartedAt(), Valid: true}, - LastBuildFinishedAt: sql.NullInt64{Int64: w.GetLastBuildFinishedAt(), Valid: true}, - LastCheckedIn: sql.NullInt64{Int64: w.GetLastCheckedIn(), Valid: true}, - BuildLimit: sql.NullInt64{Int64: w.GetBuildLimit(), Valid: true}, - } - - return worker.Nullify() -} - // convertToBuilds is a helper function that generates build objects with ID fields given a list of IDs. -func convertToBuilds(ids []string) []*library.Build { +func convertToBuilds(ids []string) []*api.Build { // create stripped build objects holding the IDs - var rBs []*library.Build + var rBs []*api.Build for _, b := range ids { id, err := strconv.ParseInt(b, 10, 64) @@ -275,7 +93,7 @@ func convertToBuilds(ids []string) []*library.Build { return nil } - build := new(library.Build) + build := new(api.Build) build.SetID(id) rBs = append(rBs, build) diff --git a/database/worker/worker_test.go b/database/worker/worker_test.go index 9a4201218..bf54eb4da 100644 --- a/database/worker/worker_test.go +++ b/database/worker/worker_test.go @@ -13,7 +13,6 @@ import ( "gorm.io/gorm" api "github.com/go-vela/server/api/types" - "github.com/go-vela/types/library" ) func TestWorker_New(t *testing.T) { @@ -108,27 +107,27 @@ func TestWorker_New(t *testing.T) { } func TestWorker_convertToBuilds(t *testing.T) { - _buildOne := new(library.Build) + _buildOne := new(api.Build) _buildOne.SetID(1) - _buildTwo := new(library.Build) + _buildTwo := new(api.Build) _buildTwo.SetID(2) // setup tests tests := []struct { name string ids []string - want []*library.Build + want []*api.Build }{ { name: "one id", ids: []string{"1"}, - want: []*library.Build{_buildOne}, + want: []*api.Build{_buildOne}, }, { name: "multiple ids", ids: []string{"1", "2"}, - want: []*library.Build{_buildOne, _buildTwo}, + want: []*api.Build{_buildOne, _buildTwo}, }, { name: "not int64", @@ -210,7 +209,7 @@ func testSqlite(t *testing.T) *engine { // testWorker is a test helper function to create a library // Worker type with all fields set to their zero values. func testWorker() *api.Worker { - b := new(library.Build) + b := new(api.Build) b.SetID(1) return &api.Worker{ @@ -221,7 +220,7 @@ func testWorker() *api.Worker { Active: new(bool), Status: new(string), LastStatusUpdateAt: new(int64), - RunningBuilds: &[]*library.Build{b}, + RunningBuilds: &[]*api.Build{b}, LastBuildStartedAt: new(int64), LastBuildFinishedAt: new(int64), LastCheckedIn: new(int64), diff --git a/internal/webhook.go b/internal/webhook.go index ace36987e..9c193fe58 100644 --- a/internal/webhook.go +++ b/internal/webhook.go @@ -29,7 +29,7 @@ type PullRequest struct { type Webhook struct { Hook *library.Hook Repo *api.Repo - Build *library.Build + Build *api.Build PullRequest PullRequest Deployment *library.Deployment } diff --git a/internal/webhook_test.go b/internal/webhook_test.go index 6b072090b..4e421854c 100644 --- a/internal/webhook_test.go +++ b/internal/webhook_test.go @@ -5,8 +5,8 @@ package internal import ( "testing" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) func TestWebhook_ShouldSkip(t *testing.T) { @@ -92,8 +92,8 @@ func TestWebhook_ShouldSkip(t *testing.T) { } } -func testPushBuild(message, title, event string) *library.Build { - b := new(library.Build) +func testPushBuild(message, title, event string) *api.Build { + b := new(api.Build) b.SetEvent(event) diff --git a/mock/server/build.go b/mock/server/build.go index 1d15a5c10..37466b910 100644 --- a/mock/server/build.go +++ b/mock/server/build.go @@ -10,6 +10,7 @@ import ( "github.com/gin-gonic/gin" + api "github.com/go-vela/server/api/types" "github.com/go-vela/types" "github.com/go-vela/types/library" ) @@ -18,7 +19,52 @@ const ( // BuildResp represents a JSON return for a single build. BuildResp = `{ "id": 1, - "repo_id": 1, + "repo": { + "id": 1, + "owner": { + "id": 1, + "name": "octocat", + "favorites": [], + "active": true, + "admin": false + }, + "org": "github", + "counter": 10, + "name": "octocat", + "full_name": "github/octocat", + "link": "https://github.com/github/octocat", + "clone": "https://github.com/github/octocat", + "branch": "main", + "build_limit": 10, + "timeout": 60, + "visibility": "public", + "private": false, + "trusted": true, + "pipeline_type": "yaml", + "topics": [], + "active": true, + "allow_events": { + "push": { + "branch": true, + "tag": true + }, + "pull_request": { + "opened": true, + "synchronize": true, + "reopened": true, + "edited": false + }, + "deployment": { + "created": true + }, + "comment": { + "created": false, + "edited": false + } + }, + "approve_build": "fork-always", + "previous_name": "" + }, "pipeline_id": 1, "number": 1, "parent": 1, @@ -171,7 +217,7 @@ const ( func getBuilds(c *gin.Context) { data := []byte(BuildsResp) - var body []library.Build + var body []api.Build _ = json.Unmarshal(data, &body) c.JSON(http.StatusOK, body) @@ -191,7 +237,7 @@ func getBuild(c *gin.Context) { data := []byte(BuildResp) - var body library.Build + var body api.Build _ = json.Unmarshal(data, &body) c.JSON(http.StatusOK, body) @@ -223,7 +269,7 @@ func getLogs(c *gin.Context) { func addBuild(c *gin.Context) { data := []byte(BuildResp) - var body library.Build + var body api.Build _ = json.Unmarshal(data, &body) c.JSON(http.StatusCreated, body) @@ -247,7 +293,7 @@ func updateBuild(c *gin.Context) { data := []byte(BuildResp) - var body library.Build + var body api.Build _ = json.Unmarshal(data, &body) c.JSON(http.StatusOK, body) @@ -286,7 +332,7 @@ func restartBuild(c *gin.Context) { data := []byte(BuildResp) - var body library.Build + var body api.Build _ = json.Unmarshal(data, &body) c.JSON(http.StatusCreated, body) @@ -340,7 +386,7 @@ func buildQueue(c *gin.Context) { data := []byte(BuildQueueResp) - var body []library.BuildQueue + var body []api.QueueBuild _ = json.Unmarshal(data, &body) c.JSON(http.StatusOK, body) diff --git a/mock/server/build_test.go b/mock/server/build_test.go index 572fa4300..0d7c4825a 100644 --- a/mock/server/build_test.go +++ b/mock/server/build_test.go @@ -7,11 +7,11 @@ import ( "reflect" "testing" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" ) func TestBuild_ActiveBuildResp(t *testing.T) { - testBuild := library.Build{} + testBuild := api.Build{} err := json.Unmarshal([]byte(BuildResp), &testBuild) if err != nil { diff --git a/queue/models/item.go b/queue/models/item.go index f0a5f4fa3..83b370d48 100644 --- a/queue/models/item.go +++ b/queue/models/item.go @@ -4,7 +4,6 @@ package models import ( api "github.com/go-vela/server/api/types" - "github.com/go-vela/types/library" ) // ItemVersion allows the worker to detect items that were queued before an Vela server @@ -15,17 +14,15 @@ const ItemVersion uint64 = 3 // Item is the queue representation of an item to publish to the queue. type Item struct { - Build *library.Build `json:"build"` - Repo *api.Repo `json:"repo"` + Build *api.Build `json:"build"` // The 0-value is the implicit ItemVersion for queued Items that pre-date adding the field. ItemVersion uint64 `json:"item_version"` } -// ToItem creates a queue item from a build, repo and user. -func ToItem(b *library.Build, r *api.Repo) *Item { +// ToItem creates a queue item from a build. +func ToItem(b *api.Build) *Item { return &Item{ Build: b, - Repo: r, ItemVersion: ItemVersion, } } diff --git a/queue/models/item_test.go b/queue/models/item_test.go index 94be05c22..ba14ef5e4 100644 --- a/queue/models/item_test.go +++ b/queue/models/item_test.go @@ -7,7 +7,6 @@ import ( "testing" api "github.com/go-vela/server/api/types" - "github.com/go-vela/types/library" ) func TestTypes_ToItem(t *testing.T) { @@ -18,9 +17,30 @@ func TestTypes_ToItem(t *testing.T) { str := "foo" e := new(api.Events) - b := &library.Build{ - ID: &num64, - RepoID: &num64, + b := &api.Build{ + ID: &num64, + Repo: &api.Repo{ + ID: &num64, + Owner: &api.User{ + ID: &num64, + Name: &str, + Token: &str, + Active: &booL, + Admin: &booL, + }, + Org: &str, + Name: &str, + FullName: &str, + Link: &str, + Clone: &str, + Branch: &str, + Timeout: &num64, + Visibility: &str, + Private: &booL, + Trusted: &booL, + Active: &booL, + AllowEvents: e, + }, Number: &num, Parent: &num, Event: &str, @@ -42,32 +62,31 @@ func TestTypes_ToItem(t *testing.T) { Ref: &str, BaseRef: &str, } - r := &api.Repo{ - ID: &num64, - Owner: &api.User{ - ID: &num64, - Name: &str, - Token: &str, - Active: &booL, - Admin: &booL, - }, - Org: &str, - Name: &str, - FullName: &str, - Link: &str, - Clone: &str, - Branch: &str, - Timeout: &num64, - Visibility: &str, - Private: &booL, - Trusted: &booL, - Active: &booL, - AllowEvents: e, - } want := &Item{ - Build: &library.Build{ - ID: &num64, - RepoID: &num64, + Build: &api.Build{ + ID: &num64, + Repo: &api.Repo{ + ID: &num64, + Owner: &api.User{ + ID: &num64, + Name: &str, + Token: &str, + Active: &booL, + Admin: &booL, + }, + Org: &str, + Name: &str, + FullName: &str, + Link: &str, + Clone: &str, + Branch: &str, + Timeout: &num64, + Visibility: &str, + Private: &booL, + Trusted: &booL, + Active: &booL, + AllowEvents: e, + }, Number: &num, Parent: &num, Event: &str, @@ -89,33 +108,11 @@ func TestTypes_ToItem(t *testing.T) { Ref: &str, BaseRef: &str, }, - Repo: &api.Repo{ - ID: &num64, - Owner: &api.User{ - ID: &num64, - Name: &str, - Token: &str, - Active: &booL, - Admin: &booL, - }, - Org: &str, - Name: &str, - FullName: &str, - Link: &str, - Clone: &str, - Branch: &str, - Timeout: &num64, - Visibility: &str, - Private: &booL, - Trusted: &booL, - Active: &booL, - AllowEvents: e, - }, ItemVersion: ItemVersion, } // run test - got := ToItem(b, r) + got := ToItem(b) if !reflect.DeepEqual(got, want) { t.Errorf("ToItem is %v, want %v", got, want) diff --git a/queue/redis/length_test.go b/queue/redis/length_test.go index cf02377aa..545f9f54a 100644 --- a/queue/redis/length_test.go +++ b/queue/redis/length_test.go @@ -17,7 +17,6 @@ func TestRedis_Length(t *testing.T) { // use global variables in redis_test.go _item := &models.Item{ Build: _build, - Repo: _repo, } // setup queue item diff --git a/queue/redis/pop_test.go b/queue/redis/pop_test.go index a5ae4fd0b..b2ade0b40 100644 --- a/queue/redis/pop_test.go +++ b/queue/redis/pop_test.go @@ -19,7 +19,6 @@ func TestRedis_Pop(t *testing.T) { // use global variables in redis_test.go _item := &models.Item{ Build: _build, - Repo: _repo, } var signed []byte diff --git a/queue/redis/push_test.go b/queue/redis/push_test.go index 75acc317e..c8fe1bc7f 100644 --- a/queue/redis/push_test.go +++ b/queue/redis/push_test.go @@ -15,7 +15,6 @@ func TestRedis_Push(t *testing.T) { // use global variables in redis_test.go _item := &models.Item{ Build: _build, - Repo: _repo, } // setup queue item diff --git a/queue/redis/redis_test.go b/queue/redis/redis_test.go index ee67e682e..474d57de9 100644 --- a/queue/redis/redis_test.go +++ b/queue/redis/redis_test.go @@ -10,7 +10,6 @@ import ( "github.com/alicebob/miniredis/v2" api "github.com/go-vela/server/api/types" - "github.com/go-vela/types/library" ) // The following functions were taken from @@ -47,8 +46,29 @@ func Strings(v []string) *[]string { return &v } var ( _signingPrivateKey = "tCIevHOBq6DdN5SSBtteXUusjjd0fOqzk2eyi0DMq04NewmShNKQeUbbp3vkvIckb4pCxc+vxUo+mYf/vzOaSg==" _signingPublicKey = "DXsJkoTSkHlG26d75LyHJG+KQsXPr8VKPpmH/78zmko=" - _build = &library.Build{ - ID: Int64(1), + _build = &api.Build{ + ID: Int64(1), + Repo: &api.Repo{ + ID: Int64(1), + Owner: &api.User{ + ID: Int64(1), + Name: String("octocat"), + Token: nil, + Active: Bool(true), + Admin: Bool(false), + }, + Org: String("github"), + Name: String("octocat"), + FullName: String("github/octocat"), + Link: String("https://github.com/github/octocat"), + Clone: String("https://github.com/github/octocat.git"), + Branch: String("main"), + Timeout: Int64(60), + Visibility: String("public"), + Private: Bool(false), + Trusted: Bool(false), + Active: Bool(true), + }, Number: Int(1), Parent: Int(1), Event: String("push"), @@ -73,28 +93,6 @@ var ( Runtime: String("docker"), Distribution: String("linux"), } - - _repo = &api.Repo{ - ID: Int64(1), - Owner: &api.User{ - ID: Int64(1), - Name: String("octocat"), - Token: nil, - Active: Bool(true), - Admin: Bool(false), - }, - Org: String("github"), - Name: String("octocat"), - FullName: String("github/octocat"), - Link: String("https://github.com/github/octocat"), - Clone: String("https://github.com/github/octocat.git"), - Branch: String("main"), - Timeout: Int64(60), - Visibility: String("public"), - Private: Bool(false), - Trusted: Bool(false), - Active: Bool(true), - } ) func TestRedis_New(t *testing.T) { diff --git a/router/middleware/build/build.go b/router/middleware/build/build.go index 3c574e3e0..06273e532 100644 --- a/router/middleware/build/build.go +++ b/router/middleware/build/build.go @@ -10,16 +10,16 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" "github.com/go-vela/server/router/middleware/user" "github.com/go-vela/server/util" - "github.com/go-vela/types/library" ) // Retrieve gets the build in the given context. -func Retrieve(c *gin.Context) *library.Build { +func Retrieve(c *gin.Context) *api.Build { return FromContext(c) } diff --git a/router/middleware/build/build_test.go b/router/middleware/build/build_test.go index 01cb48bd6..d6d600b30 100644 --- a/router/middleware/build/build_test.go +++ b/router/middleware/build/build_test.go @@ -6,21 +6,21 @@ import ( "context" "net/http" "net/http/httptest" - "reflect" "testing" "github.com/gin-gonic/gin" + "github.com/google/go-cmp/cmp" api "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/server/router/middleware/org" "github.com/go-vela/server/router/middleware/repo" - "github.com/go-vela/types/library" ) func TestBuild_Retrieve(t *testing.T) { // setup types - want := new(library.Build) + want := new(api.Build) want.SetID(1) // setup context @@ -39,10 +39,12 @@ func TestBuild_Retrieve(t *testing.T) { func TestBuild_Establish(t *testing.T) { // setup types - owner := new(api.User) + owner := testutils.APIUser().Crop() owner.SetID(1) + owner.SetName("octocat") + owner.SetToken("foo") - r := new(api.Repo) + r := testutils.APIRepo() r.SetID(1) r.SetOwner(owner) r.SetHash("baz") @@ -51,9 +53,9 @@ func TestBuild_Establish(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - want := new(library.Build) + want := new(api.Build) want.SetID(1) - want.SetRepoID(1) + want.SetRepo(r) want.SetPipelineID(0) want.SetNumber(1) want.SetParent(1) @@ -87,7 +89,7 @@ func TestBuild_Establish(t *testing.T) { want.SetApprovedAt(0) want.SetApprovedBy("") - got := new(library.Build) + got := new(api.Build) // setup database db, err := database.NewTest() @@ -98,11 +100,24 @@ func TestBuild_Establish(t *testing.T) { defer func() { _ = db.DeleteBuild(context.TODO(), want) _ = db.DeleteRepo(context.TODO(), r) + _ = db.DeleteUser(context.TODO(), owner) db.Close() }() - _, _ = db.CreateRepo(context.TODO(), r) - _, _ = db.CreateBuild(context.TODO(), want) + _, err = db.CreateUser(context.TODO(), owner) + if err != nil { + t.Errorf("unable to create test user: %v", err) + } + + _, err = db.CreateRepo(context.TODO(), r) + if err != nil { + t.Errorf("unable to create test repo: %v", err) + } + + _, err = db.CreateBuild(context.TODO(), want) + if err != nil { + t.Errorf("unable to create test build: %v", err) + } // setup context gin.SetMode(gin.TestMode) @@ -129,8 +144,8 @@ func TestBuild_Establish(t *testing.T) { t.Errorf("Establish returned %v, want %v", resp.Code, http.StatusOK) } - if !reflect.DeepEqual(got, want) { - t.Errorf("Establish is %v, want %v", got, want) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("Establish mismatch (-want +got):\n%s", diff) } } diff --git a/router/middleware/build/context.go b/router/middleware/build/context.go index 99f358add..6870f5364 100644 --- a/router/middleware/build/context.go +++ b/router/middleware/build/context.go @@ -5,7 +5,7 @@ package build import ( "context" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" ) const key = "build" @@ -16,13 +16,13 @@ type Setter interface { } // FromContext returns the Build associated with this context. -func FromContext(c context.Context) *library.Build { +func FromContext(c context.Context) *api.Build { value := c.Value(key) if value == nil { return nil } - b, ok := value.(*library.Build) + b, ok := value.(*api.Build) if !ok { return nil } @@ -32,6 +32,6 @@ func FromContext(c context.Context) *library.Build { // ToContext adds the Build to this context if it supports // the Setter interface. -func ToContext(c Setter, b *library.Build) { +func ToContext(c Setter, b *api.Build) { c.Set(key, b) } diff --git a/router/middleware/build/context_test.go b/router/middleware/build/context_test.go index 66fd2d88b..4a30a1988 100644 --- a/router/middleware/build/context_test.go +++ b/router/middleware/build/context_test.go @@ -7,13 +7,13 @@ import ( "github.com/gin-gonic/gin" - "github.com/go-vela/types/library" + api "github.com/go-vela/server/api/types" ) func TestBuild_FromContext(t *testing.T) { // setup types bID := int64(1) - want := &library.Build{ID: &bID} + want := &api.Build{ID: &bID} // setup context gin.SetMode(gin.TestMode) @@ -72,7 +72,7 @@ func TestBuild_FromContext_Empty(t *testing.T) { func TestBuild_ToContext(t *testing.T) { // setup types bID := int64(1) - want := &library.Build{ID: &bID} + want := &api.Build{ID: &bID} // setup context gin.SetMode(gin.TestMode) diff --git a/router/middleware/logger_test.go b/router/middleware/logger_test.go index 1521eba32..25e3dad14 100644 --- a/router/middleware/logger_test.go +++ b/router/middleware/logger_test.go @@ -29,11 +29,6 @@ import ( func TestMiddleware_Logger(t *testing.T) { // setup types - b := new(library.Build) - b.SetID(1) - b.SetRepoID(1) - b.SetNumber(1) - r := new(api.Repo) r.SetID(1) r.GetOwner().SetID(1) @@ -41,6 +36,11 @@ func TestMiddleware_Logger(t *testing.T) { r.SetName("bar") r.SetFullName("foo/bar") + b := new(api.Build) + b.SetID(1) + b.SetRepo(r) + b.SetNumber(1) + svc := new(library.Service) svc.SetID(1) svc.SetRepoID(1) @@ -171,9 +171,9 @@ func TestMiddleware_Logger_Sanitize(t *testing.T) { r.SetFullName("foo/bar") logRepo, _ := json.Marshal(r) - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) b.SetEmail("octocat@github.com") logBuild, _ := json.Marshal(b) diff --git a/router/middleware/perm/perm_test.go b/router/middleware/perm/perm_test.go index b34293f91..8ca690b50 100644 --- a/router/middleware/perm/perm_test.go +++ b/router/middleware/perm/perm_test.go @@ -24,7 +24,6 @@ import ( "github.com/go-vela/server/scm" "github.com/go-vela/server/scm/github" "github.com/go-vela/types/constants" - "github.com/go-vela/types/library" ) func TestPerm_MustPlatformAdmin(t *testing.T) { @@ -408,9 +407,9 @@ func TestPerm_MustBuildAccess(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) tm := &token.Manager{ @@ -497,9 +496,9 @@ func TestPerm_MustBuildAccess_PlatAdmin(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) u := new(api.User) @@ -592,9 +591,9 @@ func TestPerm_MustBuildToken_WrongBuild(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) tm := &token.Manager{ @@ -681,9 +680,9 @@ func TestPerm_MustSecretAdmin_BuildToken_Repo(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) tm := &token.Manager{ @@ -767,9 +766,9 @@ func TestPerm_MustSecretAdmin_BuildToken_Org(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) tm := &token.Manager{ @@ -853,9 +852,9 @@ func TestPerm_MustSecretAdmin_BuildToken_Shared(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) tm := &token.Manager{ @@ -1846,9 +1845,9 @@ func TestPerm_MustRead_WorkerBuildToken(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("private") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) mto := &token.MintTokenOpts{ diff --git a/router/middleware/pipeline/pipeline.go b/router/middleware/pipeline/pipeline.go index c8d8fc4dc..e2bf396ea 100644 --- a/router/middleware/pipeline/pipeline.go +++ b/router/middleware/pipeline/pipeline.go @@ -9,6 +9,7 @@ import ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" + api "github.com/go-vela/server/api/types" "github.com/go-vela/server/compiler" "github.com/go-vela/server/database" "github.com/go-vela/server/internal" @@ -74,13 +75,15 @@ func Establish() gin.HandlerFunc { return } + b := new(api.Build) + b.SetRepo(r) + // parse and compile the pipeline configuration file _, pipeline, err = compiler.FromContext(c). Duplicate(). WithCommit(p). WithMetadata(c.MustGet("metadata").(*internal.Metadata)). - WithRepo(r). - WithUser(u). + WithBuild(b). Compile(config) if err != nil { retErr := fmt.Errorf("unable to compile pipeline configuration for %s: %w", entry, err) diff --git a/router/middleware/repo/repo_test.go b/router/middleware/repo/repo_test.go index 6c683c5a5..d2bb0d512 100644 --- a/router/middleware/repo/repo_test.go +++ b/router/middleware/repo/repo_test.go @@ -13,8 +13,8 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" + "github.com/go-vela/server/database/testutils" "github.com/go-vela/server/router/middleware/org" - "github.com/go-vela/types/constants" ) func TestRepo_Retrieve(t *testing.T) { @@ -37,12 +37,11 @@ func TestRepo_Retrieve(t *testing.T) { func TestRepo_Establish(t *testing.T) { // setup types - owner := new(api.User) + owner := testutils.APIUser().Crop() owner.SetID(1) owner.SetName("foo") owner.SetActive(false) - owner.SetToken(constants.SecretMask) - owner.SetRefreshToken(constants.SecretMask) + owner.SetToken("bar") want := new(api.Repo) want.SetID(1) diff --git a/router/middleware/service/service_test.go b/router/middleware/service/service_test.go index fcf7fc585..65869cea0 100644 --- a/router/middleware/service/service_test.go +++ b/router/middleware/service/service_test.go @@ -51,9 +51,9 @@ func TestService_Establish(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) want := new(library.Service) @@ -215,9 +215,9 @@ func TestService_Establish_NoServiceParameter(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) // setup database @@ -274,9 +274,9 @@ func TestService_Establish_InvalidServiceParameter(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) // setup database @@ -330,9 +330,9 @@ func TestService_Establish_NoService(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) // setup database diff --git a/router/middleware/step/step_test.go b/router/middleware/step/step_test.go index 6e26dd5ba..b96141e5b 100644 --- a/router/middleware/step/step_test.go +++ b/router/middleware/step/step_test.go @@ -52,9 +52,9 @@ func TestStep_Establish(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) want := new(library.Step) @@ -221,9 +221,9 @@ func TestStep_Establish_NoStepParameter(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) // setup database @@ -280,9 +280,9 @@ func TestStep_Establish_InvalidStepParameter(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) // setup database @@ -339,9 +339,9 @@ func TestStep_Establish_NoStep(t *testing.T) { r.SetFullName("foo/bar") r.SetVisibility("public") - b := new(library.Build) + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) // setup database diff --git a/router/middleware/worker/worker_test.go b/router/middleware/worker/worker_test.go index a59f11190..d39d43842 100644 --- a/router/middleware/worker/worker_test.go +++ b/router/middleware/worker/worker_test.go @@ -13,7 +13,6 @@ import ( api "github.com/go-vela/server/api/types" "github.com/go-vela/server/database" - "github.com/go-vela/types/library" ) func TestWorker_Retrieve(t *testing.T) { @@ -36,7 +35,7 @@ func TestWorker_Retrieve(t *testing.T) { func TestWorker_Establish(t *testing.T) { // setup types - b := new(library.Build) + b := new(api.Build) b.SetID(1) want := new(api.Worker) @@ -47,7 +46,7 @@ func TestWorker_Establish(t *testing.T) { want.SetActive(true) want.SetStatus("available") want.SetLastStatusUpdateAt(12345) - want.SetRunningBuilds([]*library.Build{b}) + want.SetRunningBuilds([]*api.Build{b}) want.SetLastBuildStartedAt(12345) want.SetLastBuildFinishedAt(12345) want.SetLastCheckedIn(12345) diff --git a/scm/github/repo.go b/scm/github/repo.go index 712dada46..c9b143763 100644 --- a/scm/github/repo.go +++ b/scm/github/repo.go @@ -281,7 +281,7 @@ func (c *client) Update(ctx context.Context, u *api.User, r *api.Repo, hookID in } // Status sends the commit status for the given SHA from the GitHub repo. -func (c *client) Status(ctx context.Context, u *api.User, b *library.Build, org, name string) error { +func (c *client) Status(ctx context.Context, u *api.User, b *api.Build, org, name string) error { c.Logger.WithFields(logrus.Fields{ "build": b.GetNumber(), "org": org, @@ -394,7 +394,7 @@ func (c *client) Status(ctx context.Context, u *api.User, b *library.Build, org, } // StepStatus sends the commit status for the given SHA to the GitHub repo with the step as the context. -func (c *client) StepStatus(ctx context.Context, u *api.User, b *library.Build, s *library.Step, org, name string) error { +func (c *client) StepStatus(ctx context.Context, u *api.User, b *api.Build, s *library.Step, org, name string) error { c.Logger.WithFields(logrus.Fields{ "build": b.GetNumber(), "org": org, diff --git a/scm/github/repo_test.go b/scm/github/repo_test.go index d7c073892..7ef874181 100644 --- a/scm/github/repo_test.go +++ b/scm/github/repo_test.go @@ -850,9 +850,12 @@ func TestGithub_Status_Deployment(t *testing.T) { u.SetName("foo") u.SetToken("bar") - b := new(library.Build) + r := new(api.Repo) + r.SetID(1) + + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) b.SetEvent(constants.EventDeploy) b.SetStatus(constants.StatusRunning) @@ -895,9 +898,12 @@ func TestGithub_Status_Running(t *testing.T) { u.SetName("foo") u.SetToken("bar") - b := new(library.Build) + r := new(api.Repo) + r.SetID(1) + + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) b.SetEvent(constants.EventPush) b.SetStatus(constants.StatusRunning) @@ -956,9 +962,12 @@ func TestGithub_Status_Success(t *testing.T) { u.SetName("foo") u.SetToken("bar") - b := new(library.Build) + r := new(api.Repo) + r.SetID(1) + + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) b.SetEvent(constants.EventPush) b.SetStatus(constants.StatusRunning) @@ -1017,9 +1026,12 @@ func TestGithub_Status_Failure(t *testing.T) { u.SetName("foo") u.SetToken("bar") - b := new(library.Build) + r := new(api.Repo) + r.SetID(1) + + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) b.SetEvent(constants.EventPush) b.SetStatus(constants.StatusRunning) @@ -1078,9 +1090,12 @@ func TestGithub_Status_Killed(t *testing.T) { u.SetName("foo") u.SetToken("bar") - b := new(library.Build) + r := new(api.Repo) + r.SetID(1) + + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) b.SetEvent(constants.EventPush) b.SetStatus(constants.StatusRunning) @@ -1139,9 +1154,12 @@ func TestGithub_Status_Skipped(t *testing.T) { u.SetName("foo") u.SetToken("bar") - b := new(library.Build) + r := new(api.Repo) + r.SetID(1) + + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) b.SetEvent(constants.EventPush) b.SetStatus(constants.StatusSkipped) @@ -1200,9 +1218,12 @@ func TestGithub_Status_Error(t *testing.T) { u.SetName("foo") u.SetToken("bar") - b := new(library.Build) + r := new(api.Repo) + r.SetID(1) + + b := new(api.Build) b.SetID(1) - b.SetRepoID(1) + b.SetRepo(r) b.SetNumber(1) b.SetEvent(constants.EventPush) b.SetStatus(constants.StatusRunning) diff --git a/scm/github/webhook.go b/scm/github/webhook.go index 315d2ec45..0d0f1fb50 100644 --- a/scm/github/webhook.go +++ b/scm/github/webhook.go @@ -148,7 +148,7 @@ func (c *client) processPushEvent(h *library.Hook, payload *github.PushEvent) (* r.SetTopics(repo.Topics) // convert payload to library build - b := new(library.Build) + b := new(api.Build) b.SetEvent(constants.EventPush) b.SetClone(repo.GetCloneURL()) b.SetSource(payload.GetHeadCommit().GetURL()) @@ -276,7 +276,7 @@ func (c *client) processPREvent(h *library.Hook, payload *github.PullRequestEven r.SetTopics(repo.Topics) // convert payload to library build - b := new(library.Build) + b := new(api.Build) b.SetEvent(constants.EventPull) b.SetEventAction(payload.GetAction()) b.SetClone(repo.GetCloneURL()) @@ -361,7 +361,7 @@ func (c *client) processDeploymentEvent(h *library.Hook, payload *github.Deploym r.SetTopics(repo.Topics) // convert payload to library build - b := new(library.Build) + b := new(api.Build) b.SetEvent(constants.EventDeploy) b.SetEventAction(constants.ActionCreated) b.SetClone(repo.GetCloneURL()) @@ -477,7 +477,7 @@ func (c *client) processIssueCommentEvent(h *library.Hook, payload *github.Issue r.SetTopics(repo.Topics) // convert payload to library build - b := new(library.Build) + b := new(api.Build) b.SetEvent(constants.EventComment) b.SetEventAction(payload.GetAction()) b.SetClone(repo.GetCloneURL()) diff --git a/scm/github/webhook_test.go b/scm/github/webhook_test.go index 41a6a8153..baf8bf722 100644 --- a/scm/github/webhook_test.go +++ b/scm/github/webhook_test.go @@ -67,7 +67,7 @@ func TestGithub_ProcessWebhook_Push(t *testing.T) { wantRepo.SetPrivate(false) wantRepo.SetTopics([]string{"go", "vela"}) - wantBuild := new(library.Build) + wantBuild := new(api.Build) wantBuild.SetEvent("push") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") wantBuild.SetSource("https://github.com/Codertocat/Hello-World/commit/9c93babf58917cd6f6f6772b5df2b098f507ff95") @@ -145,7 +145,7 @@ func TestGithub_ProcessWebhook_Push_NoSender(t *testing.T) { wantRepo.SetPrivate(false) wantRepo.SetTopics([]string{"go", "vela"}) - wantBuild := new(library.Build) + wantBuild := new(api.Build) wantBuild.SetEvent("push") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") wantBuild.SetSource("https://github.com/Codertocat/Hello-World/commit/9c93babf58917cd6f6f6772b5df2b098f507ff95") @@ -221,7 +221,7 @@ func TestGithub_ProcessWebhook_Push_Branch_Delete(t *testing.T) { wantRepo.SetPrivate(false) wantRepo.SetTopics([]string{"go", "vela"}) - wantBuild := new(library.Build) + wantBuild := new(api.Build) wantBuild.SetEvent("delete") wantBuild.SetEventAction("branch") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") @@ -298,7 +298,7 @@ func TestGithub_ProcessWebhook_Push_Tag_Delete(t *testing.T) { wantRepo.SetPrivate(false) wantRepo.SetTopics([]string{"go", "vela"}) - wantBuild := new(library.Build) + wantBuild := new(api.Build) wantBuild.SetEvent("delete") wantBuild.SetEventAction("tag") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") @@ -357,7 +357,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { wantRepo.SetPrivate(false) wantRepo.SetTopics(nil) - wantBuild := new(library.Build) + wantBuild := new(api.Build) wantBuild.SetEvent("pull_request") wantBuild.SetEventAction("opened") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") @@ -373,7 +373,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { wantBuild.SetBaseRef("main") wantBuild.SetHeadRef("changes") - wantBuild2 := new(library.Build) + wantBuild2 := new(api.Build) wantBuild2.SetEvent("pull_request") wantBuild2.SetEventAction("labeled") wantBuild2.SetClone("https://github.com/Codertocat/Hello-World.git") @@ -389,7 +389,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { wantBuild2.SetBaseRef("main") wantBuild2.SetHeadRef("changes") - wantBuild3 := new(library.Build) + wantBuild3 := new(api.Build) wantBuild3.SetEvent("pull_request") wantBuild3.SetEventAction("unlabeled") wantBuild3.SetClone("https://github.com/Codertocat/Hello-World.git") @@ -405,7 +405,7 @@ func TestGithub_ProcessWebhook_PullRequest(t *testing.T) { wantBuild3.SetBaseRef("main") wantBuild3.SetHeadRef("changes") - wantBuild4 := new(library.Build) + wantBuild4 := new(api.Build) wantBuild4.SetEvent("pull_request") wantBuild4.SetEventAction("edited") wantBuild4.SetClone("https://github.com/Codertocat/Hello-World.git") @@ -588,7 +588,7 @@ func TestGithub_ProcessWebhook_Deployment(t *testing.T) { wantRepo.SetPrivate(false) wantRepo.SetTopics(nil) - wantBuild := new(library.Build) + wantBuild := new(api.Build) wantBuild.SetEvent(constants.EventDeploy) wantBuild.SetEventAction(constants.ActionCreated) wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") @@ -619,7 +619,7 @@ func TestGithub_ProcessWebhook_Deployment(t *testing.T) { file string hook *library.Hook repo *api.Repo - build *library.Build + build *api.Build deploymentPayload raw.StringSliceMap deployment *library.Deployment } @@ -723,7 +723,7 @@ func TestGithub_ProcessWebhook_Deployment_Commit(t *testing.T) { wantRepo.SetPrivate(false) wantRepo.SetTopics(nil) - wantBuild := new(library.Build) + wantBuild := new(api.Build) wantBuild.SetEvent(constants.EventDeploy) wantBuild.SetEventAction(constants.ActionCreated) wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") @@ -994,7 +994,7 @@ func TestGithub_ProcessWebhook_IssueComment_PR(t *testing.T) { wantRepo.SetPrivate(false) wantRepo.SetTopics(nil) - wantBuild := new(library.Build) + wantBuild := new(api.Build) wantBuild.SetEvent("comment") wantBuild.SetEventAction("created") wantBuild.SetClone("https://github.com/Codertocat/Hello-World.git") diff --git a/scm/service.go b/scm/service.go index f8f2bc14e..b65a529eb 100644 --- a/scm/service.go +++ b/scm/service.go @@ -110,10 +110,10 @@ type Service interface { Update(context.Context, *api.User, *api.Repo, int64) (bool, error) // Status defines a function that sends the // commit status for the given SHA from a repo. - Status(context.Context, *api.User, *library.Build, string, string) error + Status(context.Context, *api.User, *api.Build, string, string) error // StepStatus defines a function that sends the // commit status for the given SHA for a specified step context. - StepStatus(context.Context, *api.User, *library.Build, *library.Step, string, string) error + StepStatus(context.Context, *api.User, *api.Build, *library.Step, string, string) error // ListUserRepos defines a function that retrieves // all repos with admin rights for the user. ListUserRepos(context.Context, *api.User) ([]*api.Repo, error)