diff --git a/constants/event.go b/constants/event.go index 564064e0..9ffcc0dd 100644 --- a/constants/event.go +++ b/constants/event.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. @@ -6,21 +6,24 @@ package constants // Build and repo events. const ( - // EventPush defines the event type for build and repo push events. - EventPush = "push" - - // EventPull defines the event type for build and repo pull_request events. - EventPull = "pull_request" - - // EventTag defines the event type for build and repo tag events. - EventTag = "tag" + // EventComment defines the event type for comments added to a pull request. + EventComment = "comment" // EventDeploy defines the event type for build and repo deployment events. EventDeploy = "deployment" - // EventComment defines the event type for comments added to a pull request. - EventComment = "comment" + // EventPull defines the event type for build and repo pull_request events. + EventPull = "pull_request" + + // EventPush defines the event type for build and repo push events. + EventPush = "push" // EventRepository defines the general event type for repo management. EventRepository = "repository" + + // EventSchedule defines the event type for build and repo schedule events. + EventSchedule = "schedule" + + // EventTag defines the event type for build and repo tag events. + EventTag = "tag" ) diff --git a/constants/table.go b/constants/table.go index b81b5d16..07d81d7e 100644 --- a/constants/table.go +++ b/constants/table.go @@ -21,6 +21,9 @@ const ( // TableRepo defines the table type for the database repos table. TableRepo = "repos" + // TableSchedule defines the table type for the database schedules table. + TableSchedule = "schedules" + // TableSecret defines the table type for the database secrets table. TableSecret = "secrets" diff --git a/database/schedule.go b/database/schedule.go new file mode 100644 index 00000000..2000f4f8 --- /dev/null +++ b/database/schedule.go @@ -0,0 +1,137 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package database + +import ( + "database/sql" + "errors" + + "github.com/adhocore/gronx" + "github.com/go-vela/types/library" +) + +var ( + // ErrEmptyScheduleEntry defines the error type when a Schedule type has an empty Entry field provided. + ErrEmptyScheduleEntry = errors.New("empty schedule entry provided") + + // ErrEmptyScheduleName defines the error type when a Schedule type has an empty Name field provided. + ErrEmptyScheduleName = errors.New("empty schedule name provided") + + // ErrEmptyScheduleRepoID defines the error type when a Schedule type has an empty RepoID field provided. + ErrEmptyScheduleRepoID = errors.New("empty schedule repo_id provided") + + // ErrInvalidScheduleEntry defines the error type when a Schedule type has an invalid Entry field provided. + ErrInvalidScheduleEntry = errors.New("invalid schedule entry provided") +) + +// Schedule is the database representation of a schedule for a repo. +type Schedule struct { + ID sql.NullInt64 `sql:"id"` + RepoID sql.NullInt64 `sql:"repo_id"` + Active sql.NullBool `sql:"active"` + Name sql.NullString `sql:"name"` + Entry sql.NullString `sql:"entry"` + CreatedAt sql.NullInt64 `sql:"created_at"` + CreatedBy sql.NullString `sql:"created_by"` + UpdatedAt sql.NullInt64 `sql:"updated_at"` + UpdatedBy sql.NullString `sql:"updated_by"` + ScheduledAt sql.NullInt64 `sql:"scheduled_at"` +} + +// ScheduleFromLibrary converts the library.Schedule type to a database Schedule type. +func ScheduleFromLibrary(s *library.Schedule) *Schedule { + schedule := &Schedule{ + ID: sql.NullInt64{Int64: s.GetID(), Valid: true}, + RepoID: sql.NullInt64{Int64: s.GetRepoID(), Valid: true}, + Active: sql.NullBool{Bool: s.GetActive(), Valid: true}, + Name: sql.NullString{String: s.GetName(), Valid: true}, + Entry: sql.NullString{String: s.GetEntry(), Valid: true}, + CreatedAt: sql.NullInt64{Int64: s.GetCreatedAt(), Valid: true}, + CreatedBy: sql.NullString{String: s.GetCreatedBy(), Valid: true}, + UpdatedAt: sql.NullInt64{Int64: s.GetUpdatedAt(), Valid: true}, + UpdatedBy: sql.NullString{String: s.GetUpdatedBy(), Valid: true}, + ScheduledAt: sql.NullInt64{Int64: s.GetScheduledAt(), Valid: true}, + } + + return schedule.Nullify() +} + +// Nullify ensures the valid flag for the sql.Null types are properly set. +// +// When a field within the Schedule type is the zero value for the field, the +// valid flag is set to false causing it to be NULL in the database. +func (s *Schedule) Nullify() *Schedule { + if s == nil { + return nil + } + + // check if the ID field should be valid + s.ID.Valid = s.ID.Int64 != 0 + // check if the RepoID field should be valid + s.RepoID.Valid = s.RepoID.Int64 != 0 + // check if the ID field should be valid + s.Active.Valid = s.RepoID.Int64 != 0 + // check if the Name field should be valid + s.Name.Valid = len(s.Name.String) != 0 + // check if the Entry field should be valid + s.Entry.Valid = len(s.Entry.String) != 0 + // check if the CreatedAt field should be valid + s.CreatedAt.Valid = s.CreatedAt.Int64 != 0 + // check if the CreatedBy field should be valid + s.CreatedBy.Valid = len(s.CreatedBy.String) != 0 + // check if the UpdatedAt field should be valid + s.UpdatedAt.Valid = s.UpdatedAt.Int64 != 0 + // check if the UpdatedBy field should be valid + s.UpdatedBy.Valid = len(s.UpdatedBy.String) != 0 + // check if the ScheduledAt field should be valid + s.ScheduledAt.Valid = s.ScheduledAt.Int64 != 0 + + return s +} + +// ToLibrary converts the Schedule type to a library.Schedule type. +func (s *Schedule) ToLibrary() *library.Schedule { + return &library.Schedule{ + ID: &s.ID.Int64, + RepoID: &s.RepoID.Int64, + Active: &s.Active.Bool, + Name: &s.Name.String, + Entry: &s.Entry.String, + CreatedAt: &s.CreatedAt.Int64, + CreatedBy: &s.CreatedBy.String, + UpdatedAt: &s.UpdatedAt.Int64, + UpdatedBy: &s.UpdatedBy.String, + ScheduledAt: &s.ScheduledAt.Int64, + } +} + +// Validate verifies the necessary fields for the Schedule type are populated correctly. +func (s *Schedule) Validate() error { + // verify the RepoID field is populated + if s.RepoID.Int64 <= 0 { + return ErrEmptyScheduleRepoID + } + + // verify the Name field is populated + if len(s.Name.String) <= 0 { + return ErrEmptyScheduleName + } + + // verify the Entry field is populated + if len(s.Entry.String) <= 0 { + return ErrEmptyScheduleEntry + } + + gron := gronx.New() + if !gron.IsValid(s.Entry.String) { + return ErrInvalidScheduleEntry + } + + // ensure that all Schedule string fields that can be returned as JSON are sanitized to avoid unsafe HTML content + s.Name = sql.NullString{String: sanitize(s.Name.String), Valid: s.Name.Valid} + s.Entry = sql.NullString{String: sanitize(s.Entry.String), Valid: s.Entry.Valid} + + return nil +} diff --git a/database/schedule_test.go b/database/schedule_test.go new file mode 100644 index 00000000..ee1a06dd --- /dev/null +++ b/database/schedule_test.go @@ -0,0 +1,180 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package database + +import ( + "database/sql" + "reflect" + "testing" + "time" + + "github.com/go-vela/types/library" +) + +func TestDatabase_ScheduleFromLibrary(t *testing.T) { + s := new(library.Schedule) + s.SetID(1) + s.SetRepoID(1) + s.SetActive(true) + s.SetName("nightly") + s.SetEntry("0 0 * * *") + s.SetCreatedAt(time.Now().UTC().Unix()) + s.SetCreatedBy("user1") + s.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) + s.SetUpdatedBy("user2") + s.SetScheduledAt(time.Now().Add(time.Hour * 2).UTC().Unix()) + + want := testSchedule() + + got := ScheduleFromLibrary(s) + if !reflect.DeepEqual(got, want) { + t.Errorf("ScheduleFromAPI is %v, want %v", got, want) + } +} + +func TestDatabase_Schedule_Nullify(t *testing.T) { + tests := []struct { + name string + schedule *Schedule + want *Schedule + }{ + { + name: "schedule with fields", + schedule: testSchedule(), + want: testSchedule(), + }, + { + name: "schedule with empty fields", + schedule: new(Schedule), + want: &Schedule{ + ID: sql.NullInt64{Int64: 0, Valid: false}, + RepoID: sql.NullInt64{Int64: 0, Valid: false}, + Active: sql.NullBool{Bool: false, Valid: false}, + Name: sql.NullString{String: "", Valid: false}, + Entry: 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}, + ScheduledAt: sql.NullInt64{Int64: 0, Valid: false}, + }, + }, + { + name: "empty schedule", + schedule: nil, + want: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + got := test.schedule.Nullify() + if !reflect.DeepEqual(got, test.want) { + t.Errorf("Nullify is %v, want %v", got, test.want) + } + }) + } +} + +func TestDatabase_Schedule_ToLibrary(t *testing.T) { + want := new(library.Schedule) + want.SetID(1) + want.SetRepoID(1) + want.SetActive(true) + want.SetName("nightly") + want.SetEntry("0 0 * * *") + want.SetCreatedAt(time.Now().UTC().Unix()) + want.SetCreatedBy("user1") + want.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) + want.SetUpdatedBy("user2") + want.SetScheduledAt(time.Now().Add(time.Hour * 2).UTC().Unix()) + + got := testSchedule().ToLibrary() + if !reflect.DeepEqual(got, want) { + t.Errorf("ToLibrary is %v, want %v", got, want) + } +} + +func TestDatabase_Schedule_Validate(t *testing.T) { + tests := []struct { + name string + failure bool + schedule *Schedule + }{ + { + name: "schedule with valid fields", + failure: false, + schedule: testSchedule(), + }, + { + name: "schedule with invalid entry", + failure: true, + schedule: &Schedule{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + RepoID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "invalid", Valid: false}, + Entry: sql.NullString{String: "!@#$%^&*()", Valid: false}, + }, + }, + { + name: "schedule with missing entry", + failure: true, + schedule: &Schedule{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + RepoID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "nightly", Valid: false}, + }, + }, + { + name: "schedule with missing name", + failure: true, + schedule: &Schedule{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + RepoID: sql.NullInt64{Int64: 1, Valid: true}, + Entry: sql.NullString{String: "0 0 * * *", Valid: false}, + }, + }, + { + name: "schedule with missing repo_id", + failure: true, + schedule: &Schedule{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + Name: sql.NullString{String: "nightly", Valid: false}, + Entry: sql.NullString{String: "0 0 * * *", Valid: false}, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := test.schedule.Validate() + if test.failure { + if err == nil { + t.Errorf("Validate should have returned err") + } + return + } + if err != nil { + t.Errorf("Validate returned err: %v", err) + } + }) + } +} + +// testSchedule is a test helper function to create a Schedule type with all fields set to a fake value. +func testSchedule() *Schedule { + return &Schedule{ + ID: sql.NullInt64{Int64: 1, Valid: true}, + RepoID: sql.NullInt64{Int64: 1, Valid: true}, + Active: sql.NullBool{Bool: true, Valid: true}, + Name: sql.NullString{String: "nightly", Valid: true}, + Entry: sql.NullString{String: "0 0 * * *", Valid: true}, + CreatedAt: sql.NullInt64{Int64: time.Now().UTC().Unix(), Valid: true}, + CreatedBy: sql.NullString{String: "user1", Valid: true}, + UpdatedAt: sql.NullInt64{Int64: time.Now().Add(time.Hour * 1).UTC().Unix(), Valid: true}, + UpdatedBy: sql.NullString{String: "user2", Valid: true}, + ScheduledAt: sql.NullInt64{Int64: time.Now().Add(time.Hour * 2).UTC().Unix(), Valid: true}, + } +} diff --git a/go.mod b/go.mod index 43e849ec..0f6133c9 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/go-vela/types go 1.19 require ( + github.com/adhocore/gronx v1.6.2 github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 github.com/drone/envsubst v1.0.3 github.com/ghodss/yaml v1.0.0 diff --git a/go.sum b/go.sum index a7389d64..48c6e5fd 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/adhocore/gronx v1.6.2 h1:/Pg6cuHFJmUGRIYWhRFjb6iL9fdzNmoMPj+/r6L01KU= +github.com/adhocore/gronx v1.6.2/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/buildkite/yaml v0.0.0-20181016232759-0caa5f0796e3 h1:q+sMKdA6L8LyGVudTkpGoC73h6ak2iWSPFiFo/pFOU8= diff --git a/library/schedule.go b/library/schedule.go new file mode 100644 index 00000000..2f74c5f9 --- /dev/null +++ b/library/schedule.go @@ -0,0 +1,272 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package library + +import ( + "fmt" +) + +// Schedule is the API representation of a schedule for a repo. +// +// swagger:model Schedule +type Schedule struct { + ID *int64 `json:"id,omitempty"` + RepoID *int64 `json:"repo_id,omitempty"` + Active *bool `json:"active,omitempty"` + Name *string `json:"name,omitempty"` + Entry *string `json:"entry,omitempty"` + CreatedAt *int64 `json:"created_at,omitempty"` + CreatedBy *string `json:"created_by,omitempty"` + UpdatedAt *int64 `json:"updated_at,omitempty"` + UpdatedBy *string `json:"updated_by,omitempty"` + ScheduledAt *int64 `json:"scheduled_at,omitempty"` +} + +// GetID returns the ID field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetID() int64 { + // return zero value if Schedule type or ID field is nil + if s == nil || s.ID == nil { + return 0 + } + + return *s.ID +} + +// GetRepoID returns the RepoID field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetRepoID() int64 { + // return zero value if Schedule type or RepoID field is nil + if s == nil || s.RepoID == nil { + return 0 + } + + return *s.RepoID +} + +// GetActive returns the Active field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetActive() bool { + // return zero value if Schedule type or Active field is nil + if s == nil || s.Active == nil { + return false + } + + return *s.Active +} + +// GetName returns the Name field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetName() string { + // return zero value if Schedule type or Name field is nil + if s == nil || s.Name == nil { + return "" + } + + return *s.Name +} + +// GetEntry returns the Entry field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetEntry() string { + // return zero value if Schedule type or Entry field is nil + if s == nil || s.Entry == nil { + return "" + } + + return *s.Entry +} + +// GetCreatedAt returns the CreatedAt field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetCreatedAt() int64 { + // return zero value if Schedule type or CreatedAt field is nil + if s == nil || s.CreatedAt == nil { + return 0 + } + + return *s.CreatedAt +} + +// GetCreatedBy returns the CreatedBy field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetCreatedBy() string { + // return zero value if Schedule type or CreatedBy field is nil + if s == nil || s.CreatedBy == nil { + return "" + } + + return *s.CreatedBy +} + +// GetUpdatedAt returns the UpdatedAt field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetUpdatedAt() int64 { + // return zero value if Schedule type or UpdatedAt field is nil + if s == nil || s.UpdatedAt == nil { + return 0 + } + + return *s.UpdatedAt +} + +// GetUpdatedBy returns the UpdatedBy field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetUpdatedBy() string { + // return zero value if Schedule type or UpdatedBy field is nil + if s == nil || s.UpdatedBy == nil { + return "" + } + + return *s.UpdatedBy +} + +// GetScheduledAt returns the ScheduledAt field from the provided Schedule. If the object is nil, +// or the field within the object is nil, it returns the zero value instead. +func (s *Schedule) GetScheduledAt() int64 { + // return zero value if Schedule type or ScheduledAt field is nil + if s == nil || s.ScheduledAt == nil { + return 0 + } + + return *s.ScheduledAt +} + +// SetID sets the ID field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetID(id int64) { + // return if Schedule type is nil + if s == nil { + return + } + + s.ID = &id +} + +// SetRepoID sets the RepoID field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetRepoID(repoID int64) { + // return if Schedule type is nil + if s == nil { + return + } + + s.RepoID = &repoID +} + +// SetActive sets the Active field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetActive(active bool) { + // return if Schedule type is nil + if s == nil { + return + } + + s.Active = &active +} + +// SetName sets the Name field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetName(name string) { + // return if Schedule type is nil + if s == nil { + return + } + + s.Name = &name +} + +// SetEntry sets the Entry field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetEntry(entry string) { + // return if Schedule type is nil + if s == nil { + return + } + + s.Entry = &entry +} + +// SetCreatedAt sets the CreatedAt field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetCreatedAt(createdAt int64) { + // return if Schedule type is nil + if s == nil { + return + } + + s.CreatedAt = &createdAt +} + +// SetCreatedBy sets the CreatedBy field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetCreatedBy(createdBy string) { + // return if Schedule type is nil + if s == nil { + return + } + + s.CreatedBy = &createdBy +} + +// SetUpdatedAt sets the UpdatedAt field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetUpdatedAt(updatedAt int64) { + // return if Schedule type is nil + if s == nil { + return + } + + s.UpdatedAt = &updatedAt +} + +// SetUpdatedBy sets the UpdatedBy field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetUpdatedBy(updatedBy string) { + // return if Schedule type is nil + if s == nil { + return + } + + s.UpdatedBy = &updatedBy +} + +// SetScheduledAt sets the ScheduledAt field in the provided Schedule. If the object is nil, +// it will set nothing and immediately return making this a no-op. +func (s *Schedule) SetScheduledAt(scheduledAt int64) { + // return if Schedule type is nil + if s == nil { + return + } + + s.ScheduledAt = &scheduledAt +} + +// String implements the Stringer interface for the Schedule type. +func (s *Schedule) String() string { + return fmt.Sprintf(`{ + Active: %t, + CreatedAt: %d, + CreatedBy: %s, + Entry: %s, + ID: %d, + Name: %s, + RepoID: %d, + ScheduledAt: %d, + UpdatedAt: %d, + UpdatedBy: %s, +}`, + s.GetActive(), + s.GetCreatedAt(), + s.GetCreatedBy(), + s.GetEntry(), + s.GetID(), + s.GetName(), + s.GetRepoID(), + s.GetScheduledAt(), + s.GetUpdatedAt(), + s.GetUpdatedBy(), + ) +} diff --git a/library/schedule_test.go b/library/schedule_test.go new file mode 100644 index 00000000..9cf75313 --- /dev/null +++ b/library/schedule_test.go @@ -0,0 +1,191 @@ +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. +// +// Use of this source code is governed by the LICENSE file in this repository. + +package library + +import ( + "fmt" + "strings" + "testing" + "time" +) + +func TestLibrary_Schedule_Getters(t *testing.T) { + tests := []struct { + name string + schedule *Schedule + want *Schedule + }{ + { + name: "schedule with fields", + schedule: testSchedule(), + want: testSchedule(), + }, + { + name: "schedule with empty fields", + schedule: new(Schedule), + want: new(Schedule), + }, + { + name: "empty schedule", + schedule: nil, + want: nil, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.schedule.GetID() != test.want.GetID() { + t.Errorf("GetID is %v, want %v", test.schedule.GetID(), test.want.GetID()) + } + if test.schedule.GetRepoID() != test.want.GetRepoID() { + t.Errorf("GetRepoID is %v, want %v", test.schedule.GetRepoID(), test.want.GetRepoID()) + } + if test.schedule.GetActive() != test.want.GetActive() { + t.Errorf("GetActive is %v, want %v", test.schedule.GetActive(), test.want.GetActive()) + } + if test.schedule.GetName() != test.want.GetName() { + t.Errorf("GetName is %v, want %v", test.schedule.GetName(), test.want.GetName()) + } + if test.schedule.GetEntry() != test.want.GetEntry() { + t.Errorf("GetEntry is %v, want %v", test.schedule.GetEntry(), test.want.GetEntry()) + } + if test.schedule.GetCreatedAt() != test.want.GetCreatedAt() { + t.Errorf("GetCreatedAt is %v, want %v", test.schedule.GetCreatedAt(), test.want.GetCreatedAt()) + } + if test.schedule.GetCreatedBy() != test.want.GetCreatedBy() { + t.Errorf("GetCreatedBy is %v, want %v", test.schedule.GetCreatedBy(), test.want.GetCreatedBy()) + } + if test.schedule.GetUpdatedAt() != test.want.GetUpdatedAt() { + t.Errorf("GetUpdatedAt is %v, want %v", test.schedule.GetUpdatedAt(), test.want.GetUpdatedAt()) + } + if test.schedule.GetUpdatedBy() != test.want.GetUpdatedBy() { + t.Errorf("GetUpdatedBy is %v, want %v", test.schedule.GetUpdatedBy(), test.want.GetUpdatedBy()) + } + if test.schedule.GetScheduledAt() != test.want.GetScheduledAt() { + t.Errorf("GetScheduledAt is %v, want %v", test.schedule.GetScheduledAt(), test.want.GetScheduledAt()) + } + }) + } +} + +func TestLibrary_Schedule_Setters(t *testing.T) { + tests := []struct { + name string + schedule *Schedule + want *Schedule + }{ + { + name: "schedule with fields", + schedule: testSchedule(), + want: testSchedule(), + }, + { + name: "schedule with empty fields", + schedule: new(Schedule), + want: new(Schedule), + }, + { + name: "empty schedule", + schedule: nil, + want: nil, + }, + } + + // run tests + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + test.schedule.SetID(test.want.GetID()) + if test.schedule.GetID() != test.want.GetID() { + t.Errorf("SetID is %v, want %v", test.schedule.GetID(), test.want.GetID()) + } + test.schedule.SetRepoID(test.want.GetRepoID()) + if test.schedule.GetRepoID() != test.want.GetRepoID() { + t.Errorf("SetRepoID is %v, want %v", test.schedule.GetRepoID(), test.want.GetRepoID()) + } + test.schedule.SetActive(test.want.GetActive()) + if test.schedule.GetActive() != test.want.GetActive() { + t.Errorf("SetActive is %v, want %v", test.schedule.GetActive(), test.want.GetActive()) + } + test.schedule.SetName(test.want.GetName()) + if test.schedule.GetName() != test.want.GetName() { + t.Errorf("SetName is %v, want %v", test.schedule.GetName(), test.want.GetName()) + } + test.schedule.SetEntry(test.want.GetEntry()) + if test.schedule.GetEntry() != test.want.GetEntry() { + t.Errorf("SetEntry is %v, want %v", test.schedule.GetEntry(), test.want.GetEntry()) + } + test.schedule.SetCreatedAt(test.want.GetCreatedAt()) + if test.schedule.GetCreatedAt() != test.want.GetCreatedAt() { + t.Errorf("SetCreatedAt is %v, want %v", test.schedule.GetCreatedAt(), test.want.GetCreatedAt()) + } + test.schedule.SetCreatedBy(test.want.GetCreatedBy()) + if test.schedule.GetCreatedBy() != test.want.GetCreatedBy() { + t.Errorf("SetCreatedBy is %v, want %v", test.schedule.GetCreatedBy(), test.want.GetCreatedBy()) + } + test.schedule.SetUpdatedAt(test.want.GetUpdatedAt()) + if test.schedule.GetUpdatedAt() != test.want.GetUpdatedAt() { + t.Errorf("SetUpdatedAt is %v, want %v", test.schedule.GetUpdatedAt(), test.want.GetUpdatedAt()) + } + test.schedule.SetUpdatedBy(test.want.GetUpdatedBy()) + if test.schedule.GetUpdatedBy() != test.want.GetUpdatedBy() { + t.Errorf("SetUpdatedBy is %v, want %v", test.schedule.GetUpdatedBy(), test.want.GetUpdatedBy()) + } + test.schedule.SetScheduledAt(test.want.GetScheduledAt()) + if test.schedule.GetScheduledAt() != test.want.GetScheduledAt() { + t.Errorf("SetScheduledAt is %v, want %v", test.schedule.GetScheduledAt(), test.want.GetScheduledAt()) + } + }) + } +} + +func TestLibrary_Schedule_String(t *testing.T) { + s := testSchedule() + + want := fmt.Sprintf(`{ + Active: %t, + CreatedAt: %d, + CreatedBy: %s, + Entry: %s, + ID: %d, + Name: %s, + RepoID: %d, + ScheduledAt: %d, + UpdatedAt: %d, + UpdatedBy: %s, +}`, + s.GetActive(), + s.GetCreatedAt(), + s.GetCreatedBy(), + s.GetEntry(), + s.GetID(), + s.GetName(), + s.GetRepoID(), + s.GetScheduledAt(), + s.GetUpdatedAt(), + s.GetUpdatedBy(), + ) + + got := s.String() + if !strings.EqualFold(got, want) { + t.Errorf("String is %v, want %v", got, want) + } +} + +// testSchedule is a test helper function to create a Schedule type with all fields set to a fake value. +func testSchedule() *Schedule { + s := new(Schedule) + s.SetID(1) + s.SetRepoID(1) + s.SetActive(true) + s.SetName("nightly") + s.SetEntry("0 0 * * *") + s.SetCreatedAt(time.Now().UTC().Unix()) + s.SetCreatedBy("user1") + s.SetUpdatedAt(time.Now().Add(time.Hour * 1).UTC().Unix()) + s.SetUpdatedBy("user2") + s.SetScheduledAt(time.Now().Add(time.Hour * 2).UTC().Unix()) + + return s +} diff --git a/pipeline/ruleset.go b/pipeline/ruleset.go index e63ba0fc..4d8f4b4b 100644 --- a/pipeline/ruleset.go +++ b/pipeline/ruleset.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. diff --git a/pipeline/ruleset_test.go b/pipeline/ruleset_test.go index c0d06740..64ad3679 100644 --- a/pipeline/ruleset_test.go +++ b/pipeline/ruleset_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. @@ -63,6 +63,16 @@ func TestPipeline_Ruleset_Match(t *testing.T) { data: &RuleData{Branch: "dev", Comment: "", Event: "deployment", Repo: "octocat/hello-world", Status: "pending", Tag: "refs/heads/master", Target: "stage"}, want: false, }, + { + ruleset: &Ruleset{If: Rules{Event: []string{"schedule"}, Target: []string{"weekly"}}}, + data: &RuleData{Branch: "dev", Comment: "", Event: "schedule", Repo: "octocat/hello-world", Status: "pending", Tag: "refs/heads/master", Target: "weekly"}, + want: true, + }, + { + ruleset: &Ruleset{If: Rules{Event: []string{"schedule"}, Target: []string{"weekly"}}}, + data: &RuleData{Branch: "dev", Comment: "", Event: "schedule", Repo: "octocat/hello-world", Status: "pending", Tag: "refs/heads/master", Target: "nightly"}, + want: false, + }, { ruleset: &Ruleset{If: Rules{Status: []string{"success", "failure"}}}, data: &RuleData{Branch: "dev", Comment: "ok to test", Event: "push", Repo: "octocat/hello-world", Status: "failure", Tag: "refs/heads/master", Target: ""}, diff --git a/yaml/ruleset.go b/yaml/ruleset.go index 2358085e..664cdd4b 100644 --- a/yaml/ruleset.go +++ b/yaml/ruleset.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. diff --git a/yaml/ruleset_test.go b/yaml/ruleset_test.go index 8c959325..6f0363bc 100644 --- a/yaml/ruleset_test.go +++ b/yaml/ruleset_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Target Brands, Inc. All rights reserved. +// Copyright (c) 2023 Target Brands, Inc. All rights reserved. // // Use of this source code is governed by the LICENSE file in this repository. @@ -116,7 +116,7 @@ func TestYaml_Ruleset_UnmarshalYAML(t *testing.T) { Tag: []string{"^refs/tags/(\\d+\\.)+\\d+$"}, }, Unless: Rules{ - Event: []string{"deployment", "pull_request:opened", "pull_request:synchronize", "comment:created", "comment:edited"}, + Event: []string{"deployment", "pull_request:opened", "pull_request:synchronize", "comment:created", "comment:edited", "schedule"}, Path: []string{"foo.txt", "/foo/bar.txt"}, }, Matcher: "regexp", diff --git a/yaml/testdata/ruleset_advanced.yml b/yaml/testdata/ruleset_advanced.yml index fee9d47a..dfd92ca1 100644 --- a/yaml/testdata/ruleset_advanced.yml +++ b/yaml/testdata/ruleset_advanced.yml @@ -8,7 +8,8 @@ unless: - deployment - pull_request - comment + - schedule path: [ foo.txt, /foo/bar.txt ] matcher: regexp operator: or -continue: true +continue: true \ No newline at end of file