From 26e54c869418eb841c5cc1d31b3364459378c9b6 Mon Sep 17 00:00:00 2001 From: claire1618 <55173466+claire1618@users.noreply.github.com> Date: Fri, 22 Dec 2023 12:48:44 -0500 Subject: [PATCH] feat(deployment): add deployment table (#323) * adding deployment database table * adding deployment number to builds * fixing tests * adding deployment database test * go mod tidy * go mod tidy * test * fixing lint errors * fixing comments * fixing comments * adding created_at and created_by fields * deleting user field * deployment build changes * changing build field deployNumber to deploymentID * fixing things * changing DeployID back to DeployNumber --------- Co-authored-by: Claire.Nicholas --- constants/table.go | 3 + database/build.go | 8 ++ database/build_test.go | 4 + database/deployment.go | 183 ++++++++++++++++++++++++++ database/deployment_test.go | 255 ++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 3 +- library/build.go | 30 +++++ library/build_test.go | 16 +++ library/deployment.go | 120 ++++++++++++----- library/deployment_test.go | 44 +++++-- webhook.go | 1 + 12 files changed, 624 insertions(+), 44 deletions(-) create mode 100644 database/deployment.go create mode 100644 database/deployment_test.go diff --git a/constants/table.go b/constants/table.go index 2a73e596..ffd537c6 100644 --- a/constants/table.go +++ b/constants/table.go @@ -10,6 +10,9 @@ const ( // TableBuildExecutable defines the table type for the database build_executables table. TableBuildExecutable = "build_executables" + // TableDeployment defines the table type for the database deployments table. + TableDeployment = "deployments" + // TableHook defines the table type for the database hooks table. TableHook = "hooks" diff --git a/database/build.go b/database/build.go index d8a7e49b..69309492 100644 --- a/database/build.go +++ b/database/build.go @@ -45,6 +45,7 @@ type Build struct { 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"` @@ -170,6 +171,11 @@ func (b *Build) Nullify() *Build { b.Deploy.Valid = false } + // check if the DeployNumber field should be false + if b.DeployNumber.Int64 == 0 { + b.Deploy.Valid = false + } + // check if the Clone field should be false if len(b.Clone.String) == 0 { b.Clone.Valid = false @@ -282,6 +288,7 @@ func (b *Build) ToLibrary() *library.Build { 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) @@ -365,6 +372,7 @@ func BuildFromLibrary(b *library.Build) *Build { 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}, diff --git a/database/build_test.go b/database/build_test.go index 90458c44..976c66d2 100644 --- a/database/build_test.go +++ b/database/build_test.go @@ -55,6 +55,7 @@ func TestDatabase_Build_Nullify(t *testing.T) { 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}, @@ -121,6 +122,7 @@ func TestDatabase_Build_ToLibrary(t *testing.T) { 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") @@ -212,6 +214,7 @@ func TestDatabase_BuildFromLibrary(t *testing.T) { 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") @@ -273,6 +276,7 @@ func testBuild() *Build { 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: true}, 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}, diff --git a/database/deployment.go b/database/deployment.go new file mode 100644 index 00000000..6815229f --- /dev/null +++ b/database/deployment.go @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: Apache-2.0 + +package database + +import ( + "database/sql" + "errors" + "fmt" + + "github.com/go-vela/types/library" + "github.com/go-vela/types/raw" + "github.com/lib/pq" +) + +var ( + // ErrEmptyDeploymentNumber defines the error type when a + // Deployment type has an empty Number field provided. + ErrEmptyDeploymentNumber = errors.New("empty deployment number provided") + + // ErrEmptyDeploymentRepoID defines the error type when a + // Deployment type has an empty RepoID field provided. + ErrEmptyDeploymentRepoID = errors.New("empty deployment repo_id provided") +) + +// Deployment is the database representation of a deployment for a repo. +type Deployment struct { + ID sql.NullInt64 `sql:"id"` + Number sql.NullInt64 `sql:"number"` + RepoID sql.NullInt64 `sql:"repo_id"` + URL sql.NullString `sql:"url"` + Commit sql.NullString `sql:"commit"` + Ref sql.NullString `sql:"ref"` + Task sql.NullString `sql:"task"` + Target sql.NullString `sql:"target"` + Description sql.NullString `sql:"description"` + Payload raw.StringSliceMap `sql:"payload"` + CreatedAt sql.NullInt64 `sql:"created_at"` + CreatedBy sql.NullString `sql:"created_by"` + Builds pq.StringArray `sql:"builds" gorm:"type:varchar(50)"` +} + +// Nullify ensures the valid flag for +// the sql.Null types are properly set. +// +// When a field within the Deployment 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 *Deployment) Nullify() *Deployment { + if d == nil { + return nil + } + + // check if the ID field should be false + if d.ID.Int64 == 0 { + d.ID.Valid = false + } + + // check if the Number field should be false + if d.Number.Int64 == 0 { + d.Number.Valid = false + } + + // check if the RepoID field should be false + if d.RepoID.Int64 == 0 { + d.RepoID.Valid = false + } + + // check if the URL field should be false + if len(d.URL.String) == 0 { + d.URL.Valid = false + } + + // check if the Commit field should be false + if len(d.Commit.String) == 0 { + d.Commit.Valid = false + } + + // check if the Ref field should be false + if len(d.Ref.String) == 0 { + d.Ref.Valid = false + } + + // check if the Task field should be false + if len(d.Task.String) == 0 { + d.Task.Valid = false + } + + // check if the Target field should be false + if len(d.Target.String) == 0 { + d.Target.Valid = false + } + + // check if the Description field should be false + if len(d.Description.String) == 0 { + d.Description.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 + } + + return d +} + +// ToLibrary converts the Deployment type +// to a library Deployment type. +func (d *Deployment) ToLibrary(builds []*library.Build) *library.Deployment { + deployment := new(library.Deployment) + + deployment.SetID(d.ID.Int64) + deployment.SetNumber(d.Number.Int64) + deployment.SetRepoID(d.RepoID.Int64) + deployment.SetURL(d.URL.String) + deployment.SetCommit(d.Commit.String) + deployment.SetRef(d.Ref.String) + deployment.SetTask(d.Task.String) + deployment.SetTarget(d.Target.String) + deployment.SetDescription(d.Description.String) + deployment.SetPayload(d.Payload) + deployment.SetCreatedAt(d.CreatedAt.Int64) + deployment.SetCreatedBy(d.CreatedBy.String) + deployment.SetBuilds(builds) + + return deployment +} + +// Validate verifies the necessary fields for +// the Deployment type are populated correctly. +func (d *Deployment) Validate() error { + // verify the RepoID field is populated + if d.RepoID.Int64 <= 0 { + return ErrEmptyDeploymentRepoID + } + + // verify the Number field is populated + if d.Number.Int64 <= 0 { + return ErrEmptyDeploymentNumber + } + + // ensure that all Deployment string fields + // that can be returned as JSON are sanitized + // to avoid unsafe HTML content + d.Commit = sql.NullString{String: sanitize(d.Commit.String), Valid: d.Commit.Valid} + d.Ref = sql.NullString{String: sanitize(d.Ref.String), Valid: d.Ref.Valid} + d.Task = sql.NullString{String: sanitize(d.Task.String), Valid: d.Task.Valid} + d.Target = sql.NullString{String: sanitize(d.Target.String), Valid: d.Target.Valid} + d.Description = sql.NullString{String: sanitize(d.Description.String), Valid: d.Description.Valid} + + return nil +} + +// DeploymentFromLibrary converts the library Deployment type +// to a database Deployment type. +func DeploymentFromLibrary(d *library.Deployment) *Deployment { + buildIDs := []string{} + for _, build := range d.GetBuilds() { + buildIDs = append(buildIDs, fmt.Sprint(build.GetID())) + } + + deployment := &Deployment{ + ID: sql.NullInt64{Int64: d.GetID(), Valid: true}, + Number: sql.NullInt64{Int64: d.GetNumber(), Valid: true}, + RepoID: sql.NullInt64{Int64: d.GetRepoID(), Valid: true}, + URL: sql.NullString{String: d.GetURL(), Valid: true}, + Commit: sql.NullString{String: d.GetCommit(), Valid: true}, + Ref: sql.NullString{String: d.GetRef(), Valid: true}, + Task: sql.NullString{String: d.GetTask(), Valid: true}, + Target: sql.NullString{String: d.GetTarget(), Valid: true}, + Description: sql.NullString{String: d.GetDescription(), Valid: true}, + Payload: d.GetPayload(), + CreatedAt: sql.NullInt64{Int64: d.GetCreatedAt(), Valid: true}, + CreatedBy: sql.NullString{String: d.GetCreatedBy(), Valid: true}, + Builds: buildIDs, + } + + return deployment.Nullify() +} diff --git a/database/deployment_test.go b/database/deployment_test.go new file mode 100644 index 00000000..28f86b6e --- /dev/null +++ b/database/deployment_test.go @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: Apache-2.0 + +package database + +import ( + "database/sql" + "testing" + + "github.com/go-vela/types/library" + "github.com/go-vela/types/raw" + "github.com/google/go-cmp/cmp" + "github.com/lib/pq" +) + +func TestDatabase_Deployment_Nullify(t *testing.T) { + // setup types + var d *Deployment + + want := &Deployment{ + ID: sql.NullInt64{Int64: 0, Valid: false}, + Number: sql.NullInt64{Int64: 0, Valid: false}, + RepoID: sql.NullInt64{Int64: 0, Valid: false}, + URL: sql.NullString{String: "", Valid: false}, + Commit: sql.NullString{String: "", Valid: false}, + Ref: sql.NullString{String: "", Valid: false}, + Task: sql.NullString{String: "", Valid: false}, + Target: sql.NullString{String: "", Valid: false}, + Description: sql.NullString{String: "", Valid: false}, + Payload: nil, + CreatedAt: sql.NullInt64{Int64: 0, Valid: false}, + CreatedBy: sql.NullString{String: "", Valid: false}, + Builds: nil, + } + + // setup tests + tests := []struct { + deployment *Deployment + want *Deployment + }{ + { + deployment: testDeployment(), + want: testDeployment(), + }, + { + deployment: d, + want: nil, + }, + { + deployment: new(Deployment), + want: want, + }, + } + + // run tests + for _, test := range tests { + got := test.deployment.Nullify() + + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("(ToLibrary: -want +got):\n%s", diff) + } + } +} + +func TestDatabase_Deployment_ToLibrary(t *testing.T) { + builds := []*library.Build{} + + buildOne := new(library.Build) + buildOne.SetID(1) + buildOne.SetRepoID(1) + buildOne.SetPipelineID(1) + buildOne.SetNumber(1) + buildOne.SetParent(1) + buildOne.SetEvent("push") + buildOne.SetEventAction("") + buildOne.SetStatus("running") + buildOne.SetError("") + buildOne.SetEnqueued(1563474077) + buildOne.SetCreated(1563474076) + buildOne.SetStarted(1563474078) + buildOne.SetFinished(1563474079) + buildOne.SetDeploy("") + buildOne.SetDeployNumber(0) + buildOne.SetDeployPayload(nil) + buildOne.SetClone("https://github.com/github/octocat.git") + buildOne.SetSource("https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163") + buildOne.SetTitle("push received from https://github.com/github/octocat") + buildOne.SetMessage("First commit...") + buildOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") + buildOne.SetSender("OctoKitty") + buildOne.SetAuthor("OctoKitty") + buildOne.SetEmail("OctoKitty@github.com") + buildOne.SetLink("https://example.company.com/github/octocat/1") + buildOne.SetBranch("main") + buildOne.SetRef("refs/heads/main") + buildOne.SetBaseRef("") + buildOne.SetHeadRef("") + buildOne.SetHost("example.company.com") + buildOne.SetRuntime("docker") + buildOne.SetDistribution("linux") + buildOne.SetDeployPayload(raw.StringSliceMap{"foo": "test1", "bar": "test2"}) + buildOne.SetApprovedAt(1563474076) + buildOne.SetApprovedBy("OctoCat") + + builds = append(builds, buildOne) + + want := new(library.Deployment) + want.SetID(1) + want.SetNumber(1) + want.SetRepoID(1) + want.SetURL("https://github.com/github/octocat/deployments/1") + want.SetCommit("1234") + want.SetRef("refs/heads/main") + want.SetTask("deploy:vela") + want.SetTarget("production") + want.SetDescription("Deployment request from Vela") + want.SetPayload(raw.StringSliceMap{"foo": "test1"}) + want.SetCreatedAt(1) + want.SetCreatedBy("octocat") + want.SetBuilds(builds) + + got := testDeployment().ToLibrary(builds) + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("(ToLibrary: -want +got):\n%s", diff) + } +} + +func TestDatabase_Deployment_Validate(t *testing.T) { + // setup types + tests := []struct { + failure bool + deployment *Deployment + }{ + { + failure: false, + deployment: testDeployment(), + }, + { // no number set for deployment + failure: true, + deployment: &Deployment{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + RepoID: sql.NullInt64{Int64: 1, Valid: true}, + }, + }, + { // no repoID set for deployment + failure: true, + deployment: &Deployment{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Number: sql.NullInt64{Int64: 1, Valid: true}, + }, + }, + } + + // run tests + for _, test := range tests { + err := test.deployment.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 TestDatabase_DeploymentFromLibrary(t *testing.T) { + builds := []*library.Build{} + + buildOne := new(library.Build) + buildOne.SetID(1) + buildOne.SetRepoID(1) + buildOne.SetPipelineID(1) + buildOne.SetNumber(1) + buildOne.SetParent(1) + buildOne.SetEvent("push") + buildOne.SetEventAction("") + buildOne.SetStatus("running") + buildOne.SetError("") + buildOne.SetEnqueued(1563474077) + buildOne.SetCreated(1563474076) + buildOne.SetStarted(1563474078) + buildOne.SetFinished(1563474079) + buildOne.SetDeploy("") + buildOne.SetDeployNumber(0) + buildOne.SetDeployPayload(nil) + buildOne.SetClone("https://github.com/github/octocat.git") + buildOne.SetSource("https://github.com/github/octocat/48afb5bdc41ad69bf22588491333f7cf71135163") + buildOne.SetTitle("push received from https://github.com/github/octocat") + buildOne.SetMessage("First commit...") + buildOne.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") + buildOne.SetSender("OctoKitty") + buildOne.SetAuthor("OctoKitty") + buildOne.SetEmail("OctoKitty@github.com") + buildOne.SetLink("https://example.company.com/github/octocat/1") + buildOne.SetBranch("main") + buildOne.SetRef("refs/heads/main") + buildOne.SetBaseRef("") + buildOne.SetHeadRef("") + buildOne.SetHost("example.company.com") + buildOne.SetRuntime("docker") + buildOne.SetDistribution("linux") + buildOne.SetDeployPayload(raw.StringSliceMap{"foo": "test1", "bar": "test2"}) + buildOne.SetApprovedAt(1563474076) + buildOne.SetApprovedBy("OctoCat") + + builds = append(builds, buildOne) + + d := new(library.Deployment) + d.SetID(1) + d.SetNumber(1) + d.SetRepoID(1) + d.SetURL("https://github.com/github/octocat/deployments/1") + d.SetCommit("1234") + d.SetRef("refs/heads/main") + d.SetTask("deploy:vela") + d.SetTarget("production") + d.SetDescription("Deployment request from Vela") + d.SetPayload(raw.StringSliceMap{"foo": "test1"}) + d.SetCreatedAt(1) + d.SetCreatedBy("octocat") + d.SetBuilds(builds) + + want := testDeployment() + + // run test + got := DeploymentFromLibrary(d) + + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("(-want +got):\n%s", diff) + } +} + +// testDeployment is a test helper function to create a Deployment type with all fields set to a fake value. +func testDeployment() *Deployment { + return &Deployment{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Number: sql.NullInt64{Int64: 1, Valid: true}, + RepoID: sql.NullInt64{Int64: 1, Valid: true}, + URL: sql.NullString{String: "https://github.com/github/octocat/deployments/1", Valid: true}, + Commit: sql.NullString{String: "1234", Valid: true}, + Ref: sql.NullString{String: "refs/heads/main", Valid: true}, + Task: sql.NullString{String: "deploy:vela", Valid: true}, + Target: sql.NullString{String: "production", Valid: true}, + Description: sql.NullString{String: "Deployment request from Vela", Valid: true}, + Payload: raw.StringSliceMap{"foo": "test1"}, + CreatedAt: sql.NullInt64{Int64: 1, Valid: true}, + CreatedBy: sql.NullString{String: "octocat", Valid: true}, + Builds: pq.StringArray{"1"}, + } +} diff --git a/go.mod b/go.mod index 764f3775..161f50a7 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( require ( github.com/aymerick/douceur v0.2.0 // indirect + github.com/google/go-cmp v0.6.0 github.com/gorilla/css v1.0.0 // indirect github.com/kr/pretty v0.2.0 // indirect golang.org/x/net v0.17.0 // indirect diff --git a/go.sum b/go.sum index 30a8143f..3b490184 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,9 @@ github.com/drone/envsubst v1.0.3 h1:PCIBwNDYjs50AsLZPYdfhSATKaRg/FJmDc2D6+C2x8g= github.com/drone/envsubst v1.0.3/go.mod h1:N2jZmlMufstn1KEqvbHjw40h1KyTmnVzHcSc9bFiJ2g= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= diff --git a/library/build.go b/library/build.go index ca091267..5b919dfb 100644 --- a/library/build.go +++ b/library/build.go @@ -29,6 +29,7 @@ type Build struct { 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"` @@ -158,6 +159,7 @@ func (b *Build) Environment(workspace, channel string) map[string]string { 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/") { @@ -383,6 +385,19 @@ func (b *Build) GetDeploy() string { 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 @@ -812,6 +827,19 @@ func (b *Build) SetDeploy(v string) { 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 @@ -1073,6 +1101,7 @@ func (b *Build) String() string { Commit: %s, Created: %d, Deploy: %s, + DeployNumber: %d, DeployPayload: %s, Distribution: %s, Email: %s, @@ -1107,6 +1136,7 @@ func (b *Build) String() string { b.GetCommit(), b.GetCreated(), b.GetDeploy(), + b.GetDeployNumber(), b.GetDeployPayload(), b.GetDistribution(), b.GetEmail(), diff --git a/library/build_test.go b/library/build_test.go index 339daa90..bd0b265c 100644 --- a/library/build_test.go +++ b/library/build_test.go @@ -55,6 +55,7 @@ func TestLibrary_Build_Environment(t *testing.T) { _deploy := testBuild() _deploy.SetEvent("deployment") _deploy.SetDeploy("production") + _deploy.SetDeployNumber(0) _deploy.SetDeployPayload(map[string]string{ "foo": "test1", "bar": "test2", @@ -64,6 +65,7 @@ func TestLibrary_Build_Environment(t *testing.T) { _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", @@ -226,6 +228,7 @@ func TestLibrary_Build_Environment(t *testing.T) { "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", @@ -286,6 +289,7 @@ func TestLibrary_Build_Environment(t *testing.T) { "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": "", @@ -515,6 +519,10 @@ func TestLibrary_Build_Getters(t *testing.T) { 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()) } @@ -628,6 +636,7 @@ func TestLibrary_Build_Setters(t *testing.T) { 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()) @@ -704,6 +713,10 @@ func TestLibrary_Build_Setters(t *testing.T) { 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()) } @@ -796,6 +809,7 @@ func TestLibrary_Build_String(t *testing.T) { Commit: %s, Created: %d, Deploy: %s, + DeployNumber: %d, DeployPayload: %s, Distribution: %s, Email: %s, @@ -830,6 +844,7 @@ func TestLibrary_Build_String(t *testing.T) { b.GetCommit(), b.GetCreated(), b.GetDeploy(), + b.GetDeployNumber(), b.GetDeployPayload(), b.GetDistribution(), b.GetEmail(), @@ -882,6 +897,7 @@ func testBuild() *Build { 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") diff --git a/library/deployment.go b/library/deployment.go index a620a9e8..b37d80ff 100644 --- a/library/deployment.go +++ b/library/deployment.go @@ -13,16 +13,18 @@ import ( // swagger:model Deployment type Deployment struct { ID *int64 `json:"id,omitempty"` + Number *int64 `json:"number,omitempty"` RepoID *int64 `json:"repo_id,omitempty"` URL *string `json:"url,omitempty"` - User *string `json:"user,omitempty"` Commit *string `json:"commit,omitempty"` Ref *string `json:"ref,omitempty"` Task *string `json:"task,omitempty"` Target *string `json:"target,omitempty"` Description *string `json:"description,omitempty"` Payload *raw.StringSliceMap `json:"payload,omitempty"` - Builds *[]Build `json:"builds,omitempty"` + CreatedAt *int64 `json:"created_at,omitempty"` + CreatedBy *string `json:"created_by,omitempty"` + Builds []*Build `json:"builds,omitempty"` } // GetID returns the ID field. @@ -38,6 +40,19 @@ func (d *Deployment) GetID() int64 { return *d.ID } +// GetNumber returns the Number field. +// +// When the provided Deployment type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (d *Deployment) GetNumber() int64 { + // return zero value if Deployment type or ID field is nil + if d == nil || d.Number == nil { + return 0 + } + + return *d.Number +} + // GetRepoID returns the RepoID field. // // When the provided Deployment type is nil, or the field within @@ -64,19 +79,6 @@ func (d *Deployment) GetURL() string { return *d.URL } -// GetUser returns the User field. -// -// When the provided Deployment type is nil, or the field within -// the type is nil, it returns the zero value for the field. -func (d *Deployment) GetUser() string { - // return zero value if Deployment type or User field is nil - if d == nil || d.User == nil { - return "" - } - - return *d.User -} - // GetCommit returns the Commit field. // // When the provided Deployment type is nil, or the field within @@ -155,16 +157,42 @@ func (d *Deployment) GetPayload() map[string]string { return *d.Payload } +// GetCreatedAt returns the CreatedAt field. +// +// When the provided Deployment type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (d *Deployment) GetCreatedAt() int64 { + // return zero value if Deployment type or CreatedAt field is nil + if d == nil || d.CreatedAt == nil { + return 0 + } + + return *d.CreatedAt +} + +// GetCreatedBy returns the CreatedBy field. +// +// When the provided Deployment type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (d *Deployment) GetCreatedBy() string { + // return zero value if Deployment type or CreatedBy field is nil + if d == nil || d.CreatedBy == nil { + return "" + } + + return *d.CreatedBy +} + // GetBuilds returns the Builds field. // // When the provided Deployment type is nil, or the field within // the type is nil, it returns the zero value for the field. -func (d *Deployment) GetBuilds() []Build { +func (d *Deployment) GetBuilds() []*Build { if d == nil || d.Builds == nil { - return []Build{} + return []*Build{} } - return *d.Builds + return d.Builds } // SetID sets the ID field. @@ -180,43 +208,43 @@ func (d *Deployment) SetID(v int64) { d.ID = &v } -// SetRepoID sets the RepoID field. +// SetNumber sets the Number field. // // When the provided Deployment type is nil, it // will set nothing and immediately return. -func (d *Deployment) SetRepoID(v int64) { +func (d *Deployment) SetNumber(v int64) { // return if Deployment type is nil if d == nil { return } - d.RepoID = &v + d.Number = &v } -// SetURL sets the URL field. +// SetRepoID sets the RepoID field. // // When the provided Deployment type is nil, it // will set nothing and immediately return. -func (d *Deployment) SetURL(v string) { +func (d *Deployment) SetRepoID(v int64) { // return if Deployment type is nil if d == nil { return } - d.URL = &v + d.RepoID = &v } -// SetUser sets the User field. +// SetURL sets the URL field. // // When the provided Deployment type is nil, it // will set nothing and immediately return. -func (d *Deployment) SetUser(v string) { +func (d *Deployment) SetURL(v string) { // return if Deployment type is nil if d == nil { return } - d.User = &v + d.URL = &v } // SetCommit sets the Commit field. @@ -297,43 +325,73 @@ func (d *Deployment) SetPayload(v raw.StringSliceMap) { d.Payload = &v } +// SetCreatedAt sets the CreatedAt field. +// +// When the provided Deployment type is nil, it +// will set nothing and immediately return. +func (d *Deployment) SetCreatedAt(v int64) { + // return if Deployment type is nil + if d == nil { + return + } + + d.CreatedAt = &v +} + +// SetCreatedBy sets the CreatedBy field. +// +// When the provided Deployment type is nil, it +// will set nothing and immediately return. +func (d *Deployment) SetCreatedBy(v string) { + // return if Deployment type is nil + if d == nil { + return + } + + d.CreatedBy = &v +} + // SetBuilds sets the Builds field. // // When the provided Deployment type is nil, it // will set nothing and immediately return. -func (d *Deployment) SetBuilds(b []Build) { +func (d *Deployment) SetBuilds(b []*Build) { // return if Deployment type is nil if d == nil { return } - d.Builds = &b + d.Builds = b } // String implements the Stringer interface for the Deployment type. func (d *Deployment) String() string { return fmt.Sprintf(`{ Commit: %s, + CreatedAt: %d, + CreatedBy: %s, Description: %s, ID: %d, + Number: %d, Ref: %s, RepoID: %d, Target: %s, Task: %s, URL: %s, - User: %s, Payload: %s, Builds: %d, }`, d.GetCommit(), + d.GetCreatedAt(), + d.GetCreatedBy(), d.GetDescription(), d.GetID(), + d.GetNumber(), d.GetRef(), d.GetRepoID(), d.GetTarget(), d.GetTask(), d.GetURL(), - d.GetUser(), d.GetPayload(), len(d.GetBuilds()), ) diff --git a/library/deployment_test.go b/library/deployment_test.go index 03ce452e..3d13a0be 100644 --- a/library/deployment_test.go +++ b/library/deployment_test.go @@ -38,10 +38,6 @@ func TestLibrary_Deployment_Getters(t *testing.T) { t.Errorf("GetURL is %v, want %v", test.deployment.GetURL(), test.want.GetURL()) } - if test.deployment.GetUser() != test.want.GetUser() { - t.Errorf("GetUser is %v, want %v", test.deployment.GetUser(), test.want.GetUser()) - } - if test.deployment.GetCommit() != test.want.GetCommit() { t.Errorf("GetCommit is %v, want %v", test.deployment.GetCommit(), test.want.GetCommit()) } @@ -65,6 +61,14 @@ func TestLibrary_Deployment_Getters(t *testing.T) { if !reflect.DeepEqual(test.deployment.GetPayload(), test.want.GetPayload()) { t.Errorf("GetPayload is %v, want %v", test.deployment.GetPayload(), test.want.GetPayload()) } + + if test.deployment.GetCreatedAt() != test.want.GetCreatedAt() { + t.Errorf("GetCreatedAt is %v, want %v", test.deployment.GetCreatedAt(), test.want.GetCreatedAt()) + } + + if test.deployment.GetCreatedBy() != test.want.GetCreatedBy() { + t.Errorf("GetCreatedBy is %v, want %v", test.deployment.GetCreatedBy(), test.want.GetCreatedBy()) + } } } @@ -90,20 +94,26 @@ func TestLibrary_Deployment_Setters(t *testing.T) { // run tests for _, test := range tests { test.deployment.SetID(test.want.GetID()) + test.deployment.SetNumber(test.want.GetNumber()) test.deployment.SetRepoID(test.want.GetRepoID()) test.deployment.SetURL(test.want.GetURL()) - test.deployment.SetUser(test.want.GetUser()) test.deployment.SetCommit(test.want.GetCommit()) test.deployment.SetRef(test.want.GetRef()) test.deployment.SetTask(test.want.GetTask()) test.deployment.SetTarget(test.want.GetTarget()) test.deployment.SetDescription(test.want.GetDescription()) test.deployment.SetPayload(test.want.GetPayload()) + test.deployment.SetCreatedAt(test.want.GetCreatedAt()) + test.deployment.SetCreatedBy(test.want.GetCreatedBy()) if test.deployment.GetID() != test.want.GetID() { t.Errorf("SetID is %v, want %v", test.deployment.GetID(), test.want.GetID()) } + if test.deployment.GetNumber() != test.want.GetNumber() { + t.Errorf("SetNumber is %v, want %v", test.deployment.GetNumber(), test.want.GetNumber()) + } + if test.deployment.GetRepoID() != test.want.GetRepoID() { t.Errorf("SetRepoID is %v, want %v", test.deployment.GetRepoID(), test.want.GetRepoID()) } @@ -112,10 +122,6 @@ func TestLibrary_Deployment_Setters(t *testing.T) { t.Errorf("SetURL is %v, want %v", test.deployment.GetURL(), test.want.GetURL()) } - if test.deployment.GetUser() != test.want.GetUser() { - t.Errorf("SetUser is %v, want %v", test.deployment.GetUser(), test.want.GetUser()) - } - if test.deployment.GetCommit() != test.want.GetCommit() { t.Errorf("SetCommit is %v, want %v", test.deployment.GetCommit(), test.want.GetCommit()) } @@ -139,6 +145,14 @@ func TestLibrary_Deployment_Setters(t *testing.T) { if !reflect.DeepEqual(test.deployment.GetPayload(), test.want.GetPayload()) { t.Errorf("SetPayload is %v, want %v", test.deployment.GetPayload(), test.want.GetPayload()) } + + if test.deployment.GetCreatedAt() != test.want.GetCreatedAt() { + t.Errorf("SetCreatedAt is %v, want %v", test.deployment.GetCreatedAt(), test.want.GetCreatedAt()) + } + + if test.deployment.GetCreatedBy() != test.want.GetCreatedBy() { + t.Errorf("SetCreatedBy is %v, want %v", test.deployment.GetCreatedBy(), test.want.GetCreatedBy()) + } } } @@ -148,26 +162,30 @@ func TestLibrary_Deployment_String(t *testing.T) { want := fmt.Sprintf(`{ Commit: %s, + CreatedAt: %d, + CreatedBy: %s, Description: %s, ID: %d, + Number: %d, Ref: %s, RepoID: %d, Target: %s, Task: %s, URL: %s, - User: %s, Payload: %s, Builds: %d, }`, d.GetCommit(), + d.GetCreatedAt(), + d.GetCreatedBy(), d.GetDescription(), d.GetID(), + d.GetNumber(), d.GetRef(), d.GetRepoID(), d.GetTarget(), d.GetTask(), d.GetURL(), - d.GetUser(), d.GetPayload(), len(d.GetBuilds()), ) @@ -186,9 +204,9 @@ func testDeployment() *Deployment { d := new(Deployment) d.SetID(1) + d.SetNumber(0) d.SetRepoID(1) d.SetURL("https://api.github.com/repos/github/octocat/deployments/1") - d.SetUser("octocat") d.SetCommit("48afb5bdc41ad69bf22588491333f7cf71135163") d.SetRef("refs/heads/main") d.SetTask("vela-deploy") @@ -197,6 +215,8 @@ func testDeployment() *Deployment { d.SetPayload(map[string]string{ "foo": "test1", }) + d.SetCreatedAt(1) + d.SetCreatedBy("octocat") return d } diff --git a/webhook.go b/webhook.go index aaddd5c4..d4802cfa 100644 --- a/webhook.go +++ b/webhook.go @@ -30,6 +30,7 @@ type Webhook struct { Repo *library.Repo Build *library.Build PullRequest PullRequest + Deployment *library.Deployment } // ShouldSkip uses the build information